forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {createContext, useContext, useMemo} from 'react'
2import {type GestureResponderEvent, type Insets, type View} from 'react-native'
3
4import {useHaptics} from '#/lib/haptics'
5import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons'
6import {atoms as a, useTheme} from '#/alf'
7import {Button, type ButtonProps} from '#/components/Button'
8import {type Props as SVGIconProps} from '#/components/icons/common'
9import {Text, type TextProps} from '#/components/Typography'
10
11export const DEFAULT_HITSLOP = {top: 5, bottom: 10, left: 10, right: 10}
12
13const PostControlContext = createContext<{
14 big?: boolean
15 active?: boolean
16 color?: {color: string}
17}>({})
18PostControlContext.displayName = 'PostControlContext'
19
20// Base button style, which the the other ones extend
21export function PostControlButton({
22 ref,
23 onPress,
24 onLongPress,
25 children,
26 big,
27 active,
28 activeColor,
29 ...props
30}: Omit<ButtonProps, 'hitSlop'> & {
31 ref?: React.Ref<View>
32 active?: boolean
33 big?: boolean
34 color?: string
35 activeColor?: string
36 hitSlop?: Insets
37}) {
38 const t = useTheme()
39 const playHaptic = useHaptics()
40
41 const enableSquareButtons = useEnableSquareButtons()
42
43 const ctx = useMemo(
44 () => ({
45 big,
46 active,
47 color: {
48 color: activeColor && active ? activeColor : t.palette.contrast_500,
49 },
50 }),
51 [big, active, activeColor, t.palette.contrast_500],
52 )
53
54 const style = useMemo(
55 () => [
56 a.flex_row,
57 a.align_center,
58 a.gap_xs,
59 a.bg_transparent,
60 {padding: 5},
61 ],
62 [],
63 )
64
65 const handlePress = useMemo(() => {
66 if (!onPress) return
67 return (evt: GestureResponderEvent) => {
68 playHaptic('Light')
69 onPress(evt)
70 }
71 }, [onPress, playHaptic])
72
73 const handleLongPress = useMemo(() => {
74 if (!onLongPress) return
75 return (evt: GestureResponderEvent) => {
76 playHaptic('Heavy')
77 onLongPress(evt)
78 }
79 }, [onLongPress, playHaptic])
80
81 return (
82 <Button
83 ref={ref}
84 onPress={handlePress}
85 onLongPress={handleLongPress}
86 style={style}
87 hoverStyle={t.atoms.bg_contrast_25}
88 shape={enableSquareButtons ? 'square' : 'round'}
89 variant="ghost"
90 color="secondary"
91 {...props}
92 hitSlop={{
93 ...DEFAULT_HITSLOP,
94 ...(props.hitSlop || {}),
95 }}>
96 {typeof children === 'function' ? (
97 args => (
98 <PostControlContext.Provider value={ctx}>
99 {children(args)}
100 </PostControlContext.Provider>
101 )
102 ) : (
103 <PostControlContext.Provider value={ctx}>
104 {children}
105 </PostControlContext.Provider>
106 )}
107 </Button>
108 )
109}
110
111export function PostControlButtonIcon({
112 icon: Comp,
113 style,
114 ...rest
115}: SVGIconProps & {
116 icon: React.ComponentType<SVGIconProps>
117}) {
118 const {big, color} = useContext(PostControlContext)
119
120 return (
121 <Comp
122 style={[color, a.pointer_events_none, style]}
123 {...rest}
124 width={big ? 22 : 18}
125 />
126 )
127}
128
129export function PostControlButtonText({style, ...props}: TextProps) {
130 const {big, active, color} = useContext(PostControlContext)
131
132 return (
133 <Text
134 style={[
135 color,
136 big ? a.text_md : a.text_sm,
137 active && a.font_semi_bold,
138 style,
139 ]}
140 {...props}
141 />
142 )
143}