Skip to content
Source
Sign inSign up

FloatingActionButton.android.tsx

84 lines3.4 KB

1import type { FloatingActionButtonProps } from "./FloatingActionButton.types";
2import { NativeThemeHost } from "./NativeThemeHost.android";
3import {
4 Box,
5 ExtendedFloatingActionButton,
6 FloatingActionButton as ComposeFloatingActionButton,
7 LargeFloatingActionButton,
8 Text,
9} from "@expo/ui/jetpack-compose";
10import { defaultMinSize, height, size, width } from "@expo/ui/jetpack-compose/modifiers";
11import { View } from "react-native";
12import { useAndroidControlSizing } from "./useAndroidControlSizing";
13import { useAppearancePreferences } from "../../features/settings/appearance/AppearancePreferencesProvider";
14import { useScaledTextRole } from "../../features/settings/appearance/useScaledTextRole";
15import { SymbolView } from "./AppSymbol";
16​
17export function FloatingActionButton(props: FloatingActionButtonProps) {
18 const { themeVariables: colors } = useAppearancePreferences();
19 const typography = useScaledTextRole("footnote");
20 const { scale, iconSize: standardIconSize, fabSize, largeFabSize } = useAndroidControlSizing();
21 const buttonSize = props.variant === "large" ? largeFabSize : fabSize;
22 const primary = props.tone === "primary";
23 const containerColor = colors[primary ? "--color-primary" : "--color-secondary"];
24 const contentColor =
25 colors[primary ? "--color-primary-foreground" : "--color-secondary-foreground"];
26 const Component =
27 props.variant === "extended"
28 ? ExtendedFloatingActionButton
29 : props.variant === "large"
30 ? LargeFloatingActionButton
31 : ComposeFloatingActionButton;
32 const iconSize = props.variant === "large" ? Math.round(36 * scale) : standardIconSize;
33 return (
34 <View
35 accessible
36 accessibilityRole="button"
37 accessibilityLabel={props.label}
38 accessibilityActions={[{ name: "activate" }]}
39 onAccessibilityAction={props.onPress}
40 className={props.className}
41 style={props.style}
42 >
43 <View importantForAccessibility="no-hide-descendants">
44 <NativeThemeHost matchContents ignoreSafeAreaKeyboardInsets>
45 <Component
46 modifiers={[
47 defaultMinSize({ minWidth: buttonSize }),
48 height(buttonSize),
49 ...(props.variant === "extended" ? [] : [width(buttonSize)]),
50 ]}
51 containerColor={containerColor}
52 onClick={props.onPress}
53 expanded={props.expanded}
54 >
55 <Component.Icon>
56 <Box modifiers={[size(iconSize, iconSize)]} />
57 </Component.Icon>
58 {props.variant === "extended" ? (
59 <ExtendedFloatingActionButton.Text>
60 <Text color={contentColor} style={{ ...typography, fontWeight: "500" }}>
61 {props.label}
62 </Text>
63 </ExtendedFloatingActionButton.Text>
64 ) : null}
65 </Component>
66 </NativeThemeHost>
67 </View>
68 {/* The RN icon stays outside Compose so it cannot intercept native button taps. */}
69 <View
70 pointerEvents="none"
71 className="absolute inset-y-0 justify-center"
72 style={
73 props.variant === "extended" ? { left: 16 } : { left: 0, right: 0, alignItems: "center" }
74 }
75 >
76 <SymbolView
77 name={props.icon}
78 size={iconSize}
79 tintColorClassName={primary ? "accent-primary-foreground" : "accent-secondary-foreground"}
80 />
81 </View>
82 </View>
83 );