1import type { ReactNode } from "react";
2import { Platform, useWindowDimensions, View } from "react-native";
3
4import { cn } from "../lib/cn";
5import { AppText } from "./AppText";
6import { SymbolView, type AppSymbolName } from "./AppSymbol";
7
8export interface ListRowContentProps {
9 readonly icon?: AppSymbolName;
10 readonly label: string;
11 readonly description?: string;
12 readonly detail?: string;
13 readonly disabled?: boolean;
14}
15
16/** Shared row geometry; controls own their behavior and accessibility. */
17export function ListRowLayout({
18 icon,
19 label,
20 description,
21 detail,
22 disabled,
23 accessory,
24}: ListRowContentProps & { readonly accessory?: ReactNode }) {
25 const { fontScale } = useWindowDimensions();
26 // Leave the label room to wrap at accessibility text sizes.
27 const stackDetail = fontScale >= 1.5;
28 return (
29 <View
30 className={cn(
31 "min-h-14 flex-row items-center gap-3 px-4 py-3",
32 description && "min-h-18",
33 disabled && "opacity-45",
34 )}
35 >
36 {icon ? (
37 <View className="size-6 items-center justify-center">
38 <SymbolView
39 name={icon}
40 size={Platform.OS === "android" ? 24 : 22}
41 tintColorClassName="accent-icon"
42 type="monochrome"
43 weight="regular"
44 />
45 </View>
46 ) : null}
47 <View className="min-w-0 flex-1 gap-1">
48 <AppText className="text-base text-foreground">{label}</AppText>
49 {description ? (
50 <AppText className="text-sm text-foreground-muted">{description}</AppText>
51 ) : null}
52 {detail && stackDetail ? (
53 <AppText className="text-sm text-foreground-muted">{detail}</AppText>
54 ) : null}
55 </View>
56 {detail && !stackDetail ? (
57 <AppText
58 className="max-w-[40%] shrink text-right text-sm text-foreground-muted"
59 numberOfLines={1}
60 ellipsizeMode="middle"
61 >
62 {detail}
63 </AppText>
64 ) : null}
65 {accessory}
66 </View>
67 );
68}