114 lines · 3.3 KB · TypeScript
RawDownload
import type { ReactNode } from "react";import { Pressable, View } from "react-native";import { useSafeAreaInsets } from "react-native-safe-area-context"; import { SymbolView, type AppSymbolName } from "./AppSymbol";import { AppText as Text } from "./AppText";import { cn } from "../lib/cn"; export interface AndroidHeaderAction {  readonly accessibilityLabel: string;  readonly icon: AppSymbolName;  readonly onPress: () => void;  readonly disabled?: boolean;} export function AndroidHeaderIconButton(props: {  readonly accessibilityLabel: string;  readonly icon: AppSymbolName;  readonly onPress?: () => void;  readonly disabled?: boolean;}) {  return (    <Pressable      accessibilityLabel={props.accessibilityLabel}      accessibilityRole="button"      disabled={props.disabled}      hitSlop={8}      onPress={props.onPress}      className={cn(        "size-11 items-center justify-center rounded-full bg-subtle",        props.disabled && "opacity-55",      )}    >      <SymbolView        name={props.icon}        size={20}        tintColorClassName={props.disabled ? "accent-icon-subtle" : "accent-foreground"}        type="monochrome"      />    </Pressable>  );} export function AndroidScreenHeader(props: {  readonly title: string;  readonly subtitle?: string | null;  readonly actions?: ReadonlyArray<AndroidHeaderAction>;  readonly trailing?: ReactNode;  readonly onBack?: () => void;  readonly embedded?: boolean;  readonly hideBottomBorder?: boolean;}) {  const insets = useSafeAreaInsets();   return (    <View      className="border-b border-header-border bg-header px-3 pb-2.5"      style={{        paddingTop: props.embedded ? 8 : Math.max(insets.top, 12),        borderBottomWidth: props.hideBottomBorder ? 0 : undefined,      }}    >      <View className="min-h-12 flex-row items-center gap-2">        {props.onBack ? (          <Pressable            accessibilityLabel="Navigate up"            accessibilityRole="button"            hitSlop={8}            onPress={props.onBack}            className="-mr-2 size-11 items-center justify-center"          >            <SymbolView              name="chevron.left"              size={24}              tintColorClassName={"accent-foreground"}              type="monochrome"            />          </Pressable>        ) : null}         <View className={cn("min-w-0 flex-1", !props.onBack && "pl-1")}>          <Text numberOfLines={1} className="text-lg font-t3-bold text-foreground">            {props.title}          </Text>          {props.subtitle ? (            <Text              numberOfLines={1}              className="mt-px text-[13px] font-t3-medium text-foreground-muted"            >              {props.subtitle}            </Text>          ) : null}        </View>         {props.actions?.map((action) => (          <AndroidHeaderIconButton            key={action.accessibilityLabel}            accessibilityLabel={action.accessibilityLabel}            disabled={action.disabled}            icon={action.icon}            onPress={action.onPress}          />        ))}        {props.trailing}      </View>    </View>  );} export function AndroidSheetHeader(  props: Omit<Parameters<typeof AndroidScreenHeader>[0], "embedded">,) {  return <AndroidScreenHeader {...props} embedded />;}