forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {type ComponentProps, type JSX} from 'react'
2import {
3 type Pressable,
4 type StyleProp,
5 StyleSheet,
6 type ViewStyle,
7} from 'react-native'
8import Animated from 'react-native-reanimated'
9import {useSafeAreaInsets} from 'react-native-safe-area-context'
10
11import {PressableScale} from '#/lib/custom-animations/PressableScale'
12import {useHaptics} from '#/lib/haptics'
13import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
14import {clamp} from '#/lib/numbers'
15import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
16import {atoms as a, ios, useBreakpoints, useTheme} from '#/alf'
17import {IS_WEB} from '#/env'
18
19export interface FABProps extends ComponentProps<typeof Pressable> {
20 testID?: string
21 icon: JSX.Element
22 style?: StyleProp<ViewStyle>
23}
24
25export function FABInner({testID, icon, onPress, style, ...props}: FABProps) {
26 const insets = useSafeAreaInsets()
27 const {gtMobile} = useBreakpoints()
28 const t = useTheme()
29 const playHaptic = useHaptics()
30 const fabMinimalShellTransform = useMinimalShellFabTransform()
31
32 const enableSquareButtons = useEnableSquareButtons()
33
34 const size = gtMobile
35 ? enableSquareButtons
36 ? styles.sizeLargeSquare
37 : styles.sizeLarge
38 : enableSquareButtons
39 ? styles.sizeRegularSquare
40 : styles.sizeRegular
41
42 const tabletSpacing = gtMobile
43 ? {right: 50, bottom: 50}
44 : {right: 24, bottom: clamp(insets.bottom, 15, 60) + 15}
45
46 return (
47 <Animated.View
48 style={[
49 styles.outer,
50 size,
51 tabletSpacing,
52 !gtMobile && fabMinimalShellTransform,
53 ]}>
54 <PressableScale
55 testID={testID}
56 onPressIn={ios(() => playHaptic('Light'))}
57 onPress={evt => {
58 onPress?.(evt)
59 playHaptic('Light')
60 }}
61 onLongPress={ios((evt: any) => {
62 onPress?.(evt)
63 playHaptic('Heavy')
64 })}
65 targetScale={0.9}
66 style={[
67 enableSquareButtons ? a.rounded_sm : a.rounded_full,
68 size,
69 {backgroundColor: t.palette.primary_500},
70 a.align_center,
71 a.justify_center,
72 style,
73 ]}
74 {...props}>
75 {icon}
76 </PressableScale>
77 </Animated.View>
78 )
79}
80
81const styles = StyleSheet.create({
82 sizeRegular: {
83 width: 56,
84 height: 56,
85 borderRadius: 30,
86 },
87 sizeLarge: {
88 width: 70,
89 height: 70,
90 borderRadius: 35,
91 },
92 sizeRegularSquare: {
93 width: 56,
94 height: 56,
95 borderRadius: 10,
96 },
97 sizeLargeSquare: {
98 width: 70,
99 height: 70,
100 borderRadius: 15,
101 },
102 outer: {
103 // @ts-ignore web-only
104 position: IS_WEB ? 'fixed' : 'absolute',
105 zIndex: 1,
106 cursor: 'pointer',
107 },
108})