import type { ReactNode } from 'react'; import { useCallback } from 'react'; import type { StyleProp, ViewStyle } from 'react-native'; import { Pressable, View } from 'react-native'; import { RightLine as ChevronRight } from 'rn-motion-ui-icons/icons/right-line'; import { cn } from '../../../lib/cn'; import { useThemeColor } from '../../../theme/use-theme-color'; import { Button } from '../../buttons/Button/button'; import { Checkbox } from '../../form/Checkbox/checkbox'; import { ThemedIcon } from '../../icon/themed-icon'; import { Text } from '../../typography/Text/text'; import { Loader } from '../Loader/loader'; // ── Card row (small-screen mode) ────────────────────────────────────────────── export type TableCardProps = { row: T; id: string; isSelected: boolean; selectable: boolean; cardStyle?: StyleProp; /** UniWind classes merged onto the card (alongside `cardStyle`). */ cardClassName?: string; /** UniWind classes merged onto the selected-card background. */ selectedClassName?: string; toggleRow: (id: string) => void; renderSmallScreen: (row: T, selected: boolean) => ReactNode; testID?: string; }; export function TableCard({ row, id, isSelected, selectable, cardStyle, cardClassName, selectedClassName, toggleRow, renderSmallScreen, testID, }: TableCardProps) { const handlePress = useCallback(() => toggleRow(id), [toggleRow, id]); const handleCheckedChange = useCallback(() => toggleRow(id), [toggleRow, id]); return ( {selectable ? ( ) : null} {renderSmallScreen(row, isSelected)} ); } // ── Skeleton footer (appended while loading more rows) ──────────────────────── export type SkeletonFooterProps = { loading: boolean; hasRows: boolean; isCardMode: boolean; renderSkeletonCards: (rows: number) => ReactNode; renderSkeletonRows: (rows: number) => ReactNode; skeletonRows: number; }; /** Renders skeleton rows/cards appended after existing data during a follow-up load. */ export function SkeletonFooter({ loading, hasRows, isCardMode, renderSkeletonCards, renderSkeletonRows, skeletonRows, }: SkeletonFooterProps) { if (!(loading && hasRows)) return null; return isCardMode ? renderSkeletonCards(skeletonRows) : renderSkeletonRows(skeletonRows); } // ── Pagination footer ───────────────────────────────────────────────────────── export type PaginationFooterProps = { page: number; totalPages: number; paginationLabel?: (page: number, totalPages: number) => string; goToPreviousPage: () => void; goToNextPage: () => void; /** UniWind classes merged onto the footer container. */ footerClassName?: string; /** Replace the previous-page icon. Default: rotated ``. */ prevIcon?: ReactNode; /** Replace the next-page icon. Default: ``. */ nextIcon?: ReactNode; }; export function PaginationFooter({ page, totalPages, paginationLabel, goToPreviousPage, goToNextPage, footerClassName, prevIcon, nextIcon, }: PaginationFooterProps) { const label = paginationLabel?.(page, totalPages) ?? `${page} / ${totalPages}`; const prevDisabled = page <= 1; const nextDisabled = page >= totalPages; return ( {/* Rotated ChevronRight stands in for missing ChevronLeft */} {prevIcon ?? } {label} {nextIcon ?? } ); } // ── Load-more button footer ─────────────────────────────────────────────────── export type LoadMoreFooterProps = { onLoadMore?: () => void; loadMoreLabel: string; /** UniWind classes merged onto the footer container. */ footerClassName?: string; }; export function LoadMoreFooter({ onLoadMore, loadMoreLabel, footerClassName }: LoadMoreFooterProps) { return ( ); } // ── Loading-more spinner footer ─────────────────────────────────────────────── export type LoadingMoreFooterProps = { footerClassName?: string }; /** Renders a centered Loader row while a follow-up page/batch is fetching. */ export function LoadingMoreFooter({ footerClassName }: LoadingMoreFooterProps) { const mutedForeground = useThemeColor('muted-foreground'); return ( ); }