forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type AccessibilityRole,
3 type GestureResponderEvent,
4 type StyleProp,
5 type ViewStyle,
6} from 'react-native'
7import {type SharedValue} from 'react-native-reanimated'
8
9import type * as Dialog from '#/components/Dialog'
10import {
11 type ItemProps as MenuItemProps,
12 type RadixPassThroughTriggerProps,
13} from '#/components/Menu/types'
14
15export type {
16 GroupProps,
17 ItemIconProps,
18 ItemTextProps,
19} from '#/components/Menu/types'
20
21export type AuxiliaryViewProps = {
22 children?: React.ReactNode
23 align?: 'left' | 'right'
24}
25
26export type ItemProps = Omit<MenuItemProps, 'onPress' | 'children'> & {
27 // remove default styles (i.e. for emoji reactions)
28 unstyled?: boolean
29 onPress: (evt?: GestureResponderEvent) => void
30 children?: React.ReactNode | ((hovered: boolean) => React.ReactNode)
31 // absolute position of the parent element. if undefined, assumed to
32 // be in the context menu. use this if using AuxiliaryView
33 position?: Measurement
34}
35
36export type Measurement = {
37 x: number
38 y: number
39 width: number
40 height: number
41}
42
43export type ContextType = {
44 isOpen: boolean
45 measurement: Measurement | null
46 /* Spring animation between 0 and 1 */
47 animationSV: SharedValue<number>
48 /* Translation in Y axis to ensure everything's onscreen */
49 translationSV: SharedValue<number>
50 mode: 'full' | 'auxiliary-only'
51 open: (evt: Measurement, mode: 'full' | 'auxiliary-only') => void
52 close: () => void
53 registerHoverable: (
54 id: string,
55 rect: Measurement,
56 onTouchUp: () => void,
57 ) => void
58 hoverablesSV: SharedValue<Record<string, {id: string; rect: Measurement}>>
59 hoveredMenuItem: string | null
60 setHoveredMenuItem: React.Dispatch<React.SetStateAction<string | null>>
61 onTouchUpMenuItem: (id: string) => void
62}
63
64export type MenuContextType = {
65 align: 'left' | 'right'
66}
67
68export type ItemContextType = {
69 disabled: boolean
70}
71
72export type TriggerProps = {
73 children(props: TriggerChildProps): React.ReactNode
74 label: string
75 /**
76 * When activated, this is the accessibility label for the entire thing that has been triggered.
77 * For example, if the trigger is a message bubble, use the message content.
78 *
79 * @platform ios, android
80 */
81 contentLabel: string
82 hint?: string
83 role?: AccessibilityRole
84 style?: StyleProp<ViewStyle>
85}
86export type TriggerChildProps =
87 | {
88 isNative: true
89 control: {
90 isOpen: boolean
91 open: (mode: 'full' | 'auxiliary-only') => void
92 }
93 state: {
94 hovered: false
95 focused: false
96 pressed: false
97 }
98 /**
99 * We don't necessarily know what these will be spread on to, so we
100 * should add props one-by-one.
101 *
102 * On web, these properties are applied to a parent `Pressable`, so this
103 * object is empty.
104 */
105 props: {
106 ref: null
107 onPress: null
108 onFocus: null
109 onBlur: null
110 onPressIn: null
111 onPressOut: null
112 accessibilityHint: null
113 accessibilityLabel: string
114 accessibilityRole: null
115 }
116 }
117 | {
118 isNative: false
119 control: Dialog.DialogOuterProps['control']
120 state: {
121 hovered: false
122 focused: false
123 pressed: false
124 }
125 props: RadixPassThroughTriggerProps & {
126 onPress: () => void
127 onFocus: () => void
128 onBlur: () => void
129 onMouseEnter: () => void
130 onMouseLeave: () => void
131 accessibilityHint?: string
132 accessibilityLabel: string
133 accessibilityRole: AccessibilityRole
134 }
135 }