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 {atoms as a, ios, useBreakpoints, useTheme} from '#/alf'
16import {IS_WEB} from '#/env'
17
18export interface FABProps extends ComponentProps<typeof Pressable> {
19 testID?: string
20 icon: JSX.Element
21 style?: StyleProp<ViewStyle>
22}
23
24export function FABInner({testID, icon, onPress, style, ...props}: FABProps) {
25 const insets = useSafeAreaInsets()
26 const {gtMobile} = useBreakpoints()
27 const t = useTheme()
28 const playHaptic = useHaptics()
29 const fabMinimalShellTransform = useMinimalShellFabTransform()
30
31 const size = gtMobile ? styles.sizeLarge : styles.sizeRegular
32
33 const tabletSpacing = gtMobile
34 ? {right: 50, bottom: 50}
35 : {right: 24, bottom: clamp(insets.bottom, 15, 60) + 15}
36
37 return (
38 <Animated.View
39 style={[
40 styles.outer,
41 size,
42 tabletSpacing,
43 !gtMobile && fabMinimalShellTransform,
44 ]}>
45 <PressableScale
46 testID={testID}
47 onPressIn={ios(() => playHaptic('Light'))}
48 onPress={evt => {
49 onPress?.(evt)
50 playHaptic('Light')
51 }}
52 onLongPress={ios((evt: any) => {
53 onPress?.(evt)
54 playHaptic('Heavy')
55 })}
56 targetScale={0.9}
57 style={[
58 a.rounded_full,
59 size,
60 {backgroundColor: t.palette.primary_500},
61 a.align_center,
62 a.justify_center,
63 style,
64 ]}
65 {...props}>
66 {icon}
67 </PressableScale>
68 </Animated.View>
69 )
70}
71
72const styles = StyleSheet.create({
73 sizeRegular: {
74 width: 56,
75 height: 56,
76 borderRadius: 30,
77 },
78 sizeLarge: {
79 width: 70,
80 height: 70,
81 borderRadius: 35,
82 },
83 outer: {
84 // @ts-ignore web-only
85 position: IS_WEB ? 'fixed' : 'absolute',
86 zIndex: 1,
87 cursor: 'pointer',
88 },
89})