import { Platform, Text as NativeText, View } from "react-native"; import { cn } from "../../lib/cn"; import { MOBILE_CODE_SURFACE } from "../../lib/typography"; import type { ReviewRenderableLineRow } from "./reviewModel"; import type { ReviewHighlightedToken } from "./shikiReviewHighlighter"; export const REVIEW_MONO_FONT_FAMILY = Platform.select({ ios: "ui-monospace", android: "monospace", default: "monospace", }); export const REVIEW_DIFF_LINE_HEIGHT = MOBILE_CODE_SURFACE.rowHeight; const REVIEW_DELETE_STRIPE_COUNT = REVIEW_DIFF_LINE_HEIGHT / 2; export function renderVisibleWhitespace(value: string): string { const expandedTabs = value.replace(/\t/g, " "); return expandedTabs.replace(/^( +)/, (leading) => leading.replaceAll(" ", "\u00A0")); } export function changeTone(change: ReviewRenderableLineRow["change"]): string { if (change === "add") return "bg-emerald-500/10"; if (change === "delete") return "bg-rose-500/10"; return "bg-card"; } export function changeBarTone(change: ReviewRenderableLineRow["change"]): string { if (change === "add") return "bg-emerald-400"; if (change === "delete") return "bg-rose-400"; return "bg-border/50"; } function diffHighlightColor(change: ReviewRenderableLineRow["change"]): string | undefined { if (change === "add") return "rgba(16, 185, 129, 0.24)"; if (change === "delete") return "rgba(244, 63, 94, 0.24)"; return undefined; } export function ReviewChangeBar(props: { readonly change: ReviewRenderableLineRow["change"] }) { if (props.change === "delete") { return ( {Array.from({ length: REVIEW_DELETE_STRIPE_COUNT }, (_, index) => ( ))} ); } return ( ); } export function DiffTokenText(props: { readonly tokens: ReadonlyArray | null; readonly fallback: string; readonly change?: ReviewRenderableLineRow["change"]; readonly className?: string; }) { if (!props.tokens || props.tokens.length === 0) { return ( {renderVisibleWhitespace(props.fallback || " ")} ); } return ( {(() => { let offset = 0; return props.tokens.map((token) => { const start = offset; offset += token.content.length; const fontWeight = token.fontStyle !== null && (token.fontStyle & 2) === 2 ? ("700" as const) : ("500" as const); const fontStyle = token.fontStyle !== null && (token.fontStyle & 1) === 1 ? ("italic" as const) : ("normal" as const); return ( {token.content.length > 0 ? renderVisibleWhitespace(token.content) : " "} ); }); })()} ); }