137 lines · 4.4 KB · TypeScript
RawDownload
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 (      <View className="w-[5px] overflow-hidden" style={{ height: REVIEW_DIFF_LINE_HEIGHT }}>        <View>          {Array.from({ length: REVIEW_DELETE_STRIPE_COUNT }, (_, index) => (            <View key={index}>              <View className="w-[5px] bg-rose-400" style={{ height: 1 }} />              <View style={{ height: 1 }} />            </View>          ))}        </View>      </View>    );  }   return (    <View className="w-[5px] overflow-hidden" style={{ height: REVIEW_DIFF_LINE_HEIGHT }}>      <View className={cn("h-full w-[5px] flex-1", changeBarTone(props.change))} />    </View>  );} export function DiffTokenText(props: {  readonly tokens: ReadonlyArray<ReviewHighlightedToken> | null;  readonly fallback: string;  readonly change?: ReviewRenderableLineRow["change"];  readonly className?: string;}) {  if (!props.tokens || props.tokens.length === 0) {    return (      <NativeText        numberOfLines={1}        selectable        className={cn("font-normal text-foreground", props.className)}        style={{          fontFamily: REVIEW_MONO_FONT_FAMILY,          fontSize: MOBILE_CODE_SURFACE.fontSize,          lineHeight: MOBILE_CODE_SURFACE.rowHeight,        }}      >        {renderVisibleWhitespace(props.fallback || " ")}      </NativeText>    );  }   return (    <NativeText      numberOfLines={1}      selectable      className={cn("font-normal text-foreground", props.className)}      style={{        fontFamily: REVIEW_MONO_FONT_FAMILY,        fontSize: MOBILE_CODE_SURFACE.fontSize,        lineHeight: MOBILE_CODE_SURFACE.rowHeight,      }}    >      {(() => {        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 (            <NativeText              key={`${start}:${token.content.length}:${token.color ?? ""}:${token.fontStyle ?? ""}`}              selectable              style={{                color: token.color ?? undefined,                fontFamily: REVIEW_MONO_FONT_FAMILY,                fontWeight,                fontStyle,                backgroundColor:                  token.diffHighlight && props.change                    ? diffHighlightColor(props.change)                    : undefined,                borderRadius: token.diffHighlight ? 4 : undefined,              }}            >              {token.content.length > 0 ? renderVisibleWhitespace(token.content) : " "}            </NativeText>          );        });      })()}    </NativeText>  );}