1import {
2 Box,
3 Button,
4 LoadingIndicator,
5 FilledTonalButton,
6 Host,
7 Row,
8 Text,
9 TextButton,
10} from "@expo/ui/jetpack-compose";
11import { defaultMinSize, fillMaxWidth, size } from "@expo/ui/jetpack-compose/modifiers";
12import { View } from "react-native";
13
14import { useAppearancePreferences } from "../features/settings/appearance/AppearancePreferencesProvider";
15import { useScaledTextRole } from "../features/settings/appearance/useScaledTextRole";
16import type { MaterialButtonProps } from "./MaterialButton";
17import { useAndroidControlSizing } from "./useAndroidControlSizing";
18
19export function MaterialButton(props: MaterialButtonProps) {
20 const { themeAppearance, themeVariables: colors } = useAppearancePreferences();
21 const typography = useScaledTextRole("footnote");
22 const { scale, mediumIconSize } = useAndroidControlSizing();
23 const tone = props.tone ?? "secondary";
24 const Component =
25 tone === "text" ? TextButton : tone === "secondary" ? FilledTonalButton : Button;
26 const containerColor =
27 tone === "primary"
28 ? colors["--color-primary"]
29 : tone === "danger"
30 ? colors["--color-danger"]
31 : tone === "text"
32 ? "#00000000"
33 : colors["--color-secondary"];
34 const contentColor =
35 tone === "primary"
36 ? colors["--color-primary-foreground"]
37 : tone === "danger"
38 ? colors["--color-danger-foreground"]
39 : tone === "text"
40 ? colors["--color-primary-text"]
41 : colors["--color-secondary-foreground"];
42 return (
43 <View
44 accessible
45 accessibilityRole="button"
46 accessibilityLabel={props.label}
47 accessibilityState={{
48 disabled: Boolean(props.disabled || props.loading),
49 busy: Boolean(props.loading),
50 }}
51 accessibilityActions={[{ name: "activate" }]}
52 onAccessibilityAction={() => {
53 if (!props.disabled && !props.loading) props.onPress();
54 }}
55 style={props.fullWidth ? { width: "100%" } : { alignSelf: "flex-start" }}
56 >
57 <View importantForAccessibility="no-hide-descendants">
58 <Host
59 matchContents={props.fullWidth ? { vertical: true } : true}
60 colorScheme={themeAppearance}
61 ignoreSafeAreaKeyboardInsets
62 style={props.fullWidth ? { width: "100%" } : { alignSelf: "flex-start" }}
63 >
64 <Component
65 enabled={!props.disabled && !props.loading}
66 onClick={props.onPress}
67 modifiers={[
68 defaultMinSize({ minHeight: 48 }),
69 ...(props.fullWidth ? [fillMaxWidth()] : []),
70 ]}
71 colors={{
72 containerColor,
73 contentColor,
74 disabledContainerColor: colors["--color-subtle-strong"],
75 disabledContentColor: colors["--color-foreground-muted"],
76 }}
77 >
78 <Row verticalAlignment="center">
79 {props.loading ? (
80 <>
81 <LoadingIndicator
82 modifiers={[size(mediumIconSize, mediumIconSize)]}
83 color={colors["--color-foreground-muted"]}
84 />
85 <Box modifiers={[size(8 * scale, 1)]} />
86 </>
87 ) : null}
88 <Text style={{ ...typography, fontWeight: "500" }}>{props.label}</Text>
89 </Row>
90 </Component>
91 </Host>
92 </View>
93 </View>
94 );
95}