import React, { type ReactNode } from "react";
import { Pressable, Text, View } from "react-native";
import { StyleSheet, withUnistyles } from "react-native-unistyles";
import type { CountedCheckPresentation } from "@/git/check-presentation";
import { CONTROL_HEIGHTS } from "@/components/ui/control-geometry";
import {
CheckPresentationIcon,
getCheckPresentationTone,
type CheckPresentationTone,
} from "@/git/check-presentation.view";
import { ChevronDown, ChevronRight } from "lucide-react-native";
import type { Theme } from "@/styles/theme";
const ThemedChevronDown = withUnistyles(ChevronDown);
const ThemedChevronRight = withUnistyles(ChevronRight);
export const foregroundMutedColorMapping = (theme: Theme) => ({
color: theme.colors.foregroundMuted,
});
export const successColorMapping = (theme: Theme) => ({ color: theme.colors.statusSuccess });
export const dangerColorMapping = (theme: Theme) => ({ color: theme.colors.statusDanger });
export const warningColorMapping = (theme: Theme) => ({ color: theme.colors.statusWarning });
interface SectionProps {
title: string;
open: boolean;
onToggle: () => void;
summary: ReactNode;
children: ReactNode;
accessibilityLabel?: string;
}
export function Section({
title,
open,
onToggle,
summary,
children,
accessibilityLabel,
}: SectionProps) {
return (
{open ? (
) : (
)}
{title}
{summary}
{open ? {children} : null}
);
}
export type SummaryPillVariant = CheckPresentationTone;
export function SummaryPill({
count,
icon,
variant,
testID,
}: {
count: number;
icon: ReactNode;
variant: SummaryPillVariant;
testID?: string;
}) {
if (count === 0) return null;
return (
{icon}
{count}
);
}
function summaryPillTextStyle(variant: SummaryPillVariant) {
if (variant === "success") return sectionKitStyles.summaryPillSuccessText;
if (variant === "danger") return sectionKitStyles.summaryPillDangerText;
if (variant === "warning") return sectionKitStyles.summaryPillWarningText;
return sectionKitStyles.summaryPillMutedText;
}
export function CheckPresentationSummaryPill({
count,
presentation,
testID,
}: {
count: number;
presentation: CountedCheckPresentation;
testID?: string;
}) {
if (count === 0) return null;
return (
{count}
);
}
export const sectionKitStyles = StyleSheet.create((theme) => ({
sectionHeader: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
},
sectionTitle: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.medium,
color: theme.colors.foregroundMuted,
},
sectionBody: {
paddingBottom: theme.spacing[3],
},
summaryWrap: {
marginLeft: "auto",
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
},
summaryPill: {
flexDirection: "row",
alignItems: "center",
gap: 3,
},
summaryPillSuccessText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.normal,
color: theme.colors.statusSuccess,
},
summaryPillDangerText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.normal,
color: theme.colors.statusDanger,
},
summaryPillWarningText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.normal,
color: theme.colors.statusWarning,
},
summaryPillMutedText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.normal,
color: theme.colors.foregroundMuted,
},
emptyText: {
fontSize: theme.fontSize.sm,
color: theme.colors.foregroundMuted,
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
},
checkRow: {
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
// Fixed, not minHeight plus padding. A row's trailing slot holds an sm Button
// (28pt), which stacked on the vertical padding and made rows with an
// "Add to chat" button taller than rows without one. The row is single-line by
// construction, so it declares a height the button fits inside instead.
height: CONTROL_HEIGHTS.sm + theme.spacing[1],
},
checkName: {
fontSize: theme.fontSize.base,
fontWeight: theme.fontWeight.normal,
color: theme.colors.foreground,
flexShrink: 1,
},
checkWorkflow: {
fontSize: theme.fontSize.sm,
color: theme.colors.foregroundMuted,
flexShrink: 1,
},
checkTrailing: {
marginLeft: "auto",
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[2],
},
checkDuration: {
fontSize: theme.fontSize.sm,
color: theme.colors.foregroundMuted,
},
}));