forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {memo, useMemo, useState} from 'react'
2import {type Insets} from 'react-native'
3import {
4 type AppBskyFeedDefs,
5 type AppBskyFeedPost,
6 type AppBskyFeedThreadgate,
7 type RichText as RichTextAPI,
8} from '@atproto/api'
9import {msg} from '@lingui/macro'
10import {useLingui} from '@lingui/react'
11
12import {type Shadow} from '#/state/cache/post-shadow'
13import {EventStopper} from '#/view/com/util/EventStopper'
14import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
15import {useMenuControl} from '#/components/Menu'
16import * as Menu from '#/components/Menu'
17import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
18import {PostMenuItems} from './PostMenuItems'
19
20let PostMenuButton = ({
21 testID,
22 post,
23 postFeedContext,
24 postReqId,
25 big,
26 record,
27 richText,
28 timestamp,
29 threadgateRecord,
30 onShowLess,
31 hitSlop,
32 logContext,
33}: {
34 testID: string
35 post: Shadow<AppBskyFeedDefs.PostView>
36 postFeedContext: string | undefined
37 postReqId: string | undefined
38 big?: boolean
39 record: AppBskyFeedPost.Record
40 richText: RichTextAPI
41 timestamp: string
42 threadgateRecord?: AppBskyFeedThreadgate.Record
43 onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
44 hitSlop?: Insets
45 logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
46}): React.ReactNode => {
47 const {_} = useLingui()
48
49 const menuControl = useMenuControl()
50 const [hasBeenOpen, setHasBeenOpen] = useState(false)
51 const lazyMenuControl = useMemo(
52 () => ({
53 ...menuControl,
54 open() {
55 setHasBeenOpen(true)
56 // HACK. We need the state update to be flushed by the time
57 // menuControl.open() fires but RN doesn't expose flushSync.
58 setTimeout(menuControl.open)
59 },
60 }),
61 [menuControl, setHasBeenOpen],
62 )
63 return (
64 <EventStopper onKeyDown={false}>
65 <Menu.Root control={lazyMenuControl}>
66 <Menu.Trigger label={_(msg`Open post options menu`)}>
67 {({props}) => {
68 return (
69 <PostControlButton
70 testID="postDropdownBtn"
71 big={big}
72 label={props.accessibilityLabel}
73 {...props}
74 hitSlop={hitSlop}>
75 <PostControlButtonIcon icon={DotsHorizontal} />
76 </PostControlButton>
77 )
78 }}
79 </Menu.Trigger>
80 {hasBeenOpen && (
81 // Lazily initialized. Once mounted, they stay mounted.
82 <PostMenuItems
83 testID={testID}
84 post={post}
85 postFeedContext={postFeedContext}
86 postReqId={postReqId}
87 record={record}
88 richText={richText}
89 timestamp={timestamp}
90 threadgateRecord={threadgateRecord}
91 onShowLess={onShowLess}
92 logContext={logContext}
93 />
94 )}
95 </Menu.Root>
96 </EventStopper>
97 )
98}
99
100PostMenuButton = memo(PostMenuButton)
101export {PostMenuButton}