mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at remove-preload 304 lines 7.7 kB view raw
1/* eslint-disable react/prop-types */ 2 3import React from 'react' 4import {Pressable, StyleProp, View, ViewStyle} from 'react-native' 5import {msg} from '@lingui/macro' 6import {useLingui} from '@lingui/react' 7import * as DropdownMenu from '@radix-ui/react-dropdown-menu' 8 9import {atoms as a, flatten, useTheme, web} from '#/alf' 10import * as Dialog from '#/components/Dialog' 11import {useInteractionState} from '#/components/hooks/useInteractionState' 12import {Context} from '#/components/Menu/context' 13import { 14 ContextType, 15 GroupProps, 16 ItemIconProps, 17 ItemProps, 18 ItemTextProps, 19 RadixPassThroughTriggerProps, 20 TriggerProps, 21} from '#/components/Menu/types' 22import {Portal} from '#/components/Portal' 23import {Text} from '#/components/Typography' 24 25export function useMenuControl(): Dialog.DialogControlProps { 26 const id = React.useId() 27 const [isOpen, setIsOpen] = React.useState(false) 28 29 return React.useMemo( 30 () => ({ 31 id, 32 ref: {current: null}, 33 isOpen, 34 open() { 35 setIsOpen(true) 36 }, 37 close() { 38 setIsOpen(false) 39 }, 40 }), 41 [id, isOpen, setIsOpen], 42 ) 43} 44 45export function useMemoControlContext() { 46 return React.useContext(Context) 47} 48 49export function Root({ 50 children, 51 control, 52}: React.PropsWithChildren<{ 53 control?: Dialog.DialogOuterProps['control'] 54}>) { 55 const {_} = useLingui() 56 const defaultControl = useMenuControl() 57 const context = React.useMemo<ContextType>( 58 () => ({ 59 control: control || defaultControl, 60 }), 61 [control, defaultControl], 62 ) 63 const onOpenChange = React.useCallback( 64 (open: boolean) => { 65 if (context.control.isOpen && !open) { 66 context.control.close() 67 } else if (!context.control.isOpen && open) { 68 context.control.open() 69 } 70 }, 71 [context.control], 72 ) 73 74 return ( 75 <Context.Provider value={context}> 76 {context.control.isOpen && ( 77 <Portal> 78 <Pressable 79 style={[a.fixed, a.inset_0, a.z_50]} 80 onPress={() => context.control.close()} 81 accessibilityHint="" 82 accessibilityLabel={_( 83 msg`Context menu backdrop, click to close the menu.`, 84 )} 85 /> 86 </Portal> 87 )} 88 <DropdownMenu.Root 89 open={context.control.isOpen} 90 onOpenChange={onOpenChange}> 91 {children} 92 </DropdownMenu.Root> 93 </Context.Provider> 94 ) 95} 96 97const RadixTriggerPassThrough = React.forwardRef( 98 ( 99 props: { 100 children: ( 101 props: RadixPassThroughTriggerProps & { 102 ref: React.Ref<any> 103 }, 104 ) => React.ReactNode 105 }, 106 ref, 107 ) => { 108 // @ts-expect-error Radix provides no types of this stuff 109 return props.children({...props, ref}) 110 }, 111) 112RadixTriggerPassThrough.displayName = 'RadixTriggerPassThrough' 113 114export function Trigger({children, label}: TriggerProps) { 115 const {control} = React.useContext(Context) 116 const { 117 state: hovered, 118 onIn: onMouseEnter, 119 onOut: onMouseLeave, 120 } = useInteractionState() 121 const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 122 123 return ( 124 <DropdownMenu.Trigger asChild> 125 <RadixTriggerPassThrough> 126 {props => 127 children({ 128 isNative: false, 129 control, 130 state: { 131 hovered, 132 focused, 133 pressed: false, 134 }, 135 props: { 136 ...props, 137 // No-op override to prevent false positive that interprets mobile scroll as a tap. 138 // This requires the custom onPress handler below to compensate. 139 // https://github.com/radix-ui/primitives/issues/1912 140 onPointerDown: undefined, 141 onPress: () => { 142 if (window.event instanceof KeyboardEvent) { 143 // The onPointerDown hack above is not relevant to this press, so don't do anything. 144 return 145 } 146 // Compensate for the disabled onPointerDown above by triggering it manually. 147 if (control.isOpen) { 148 control.close() 149 } else { 150 control.open() 151 } 152 }, 153 onFocus: onFocus, 154 onBlur: onBlur, 155 onMouseEnter, 156 onMouseLeave, 157 accessibilityLabel: label, 158 }, 159 }) 160 } 161 </RadixTriggerPassThrough> 162 </DropdownMenu.Trigger> 163 ) 164} 165 166export function Outer({ 167 children, 168 style, 169}: React.PropsWithChildren<{ 170 showCancel?: boolean 171 style?: StyleProp<ViewStyle> 172}>) { 173 const t = useTheme() 174 175 return ( 176 <DropdownMenu.Portal> 177 <DropdownMenu.Content sideOffset={5} loop aria-label="Test"> 178 <View 179 style={[ 180 a.rounded_sm, 181 a.p_xs, 182 t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25, 183 t.atoms.shadow_md, 184 style, 185 ]}> 186 {children} 187 </View> 188 189 {/* Disabled until we can fix positioning 190 <DropdownMenu.Arrow 191 className="DropdownMenuArrow" 192 fill={ 193 (t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25) 194 .backgroundColor 195 } 196 /> 197 */} 198 </DropdownMenu.Content> 199 </DropdownMenu.Portal> 200 ) 201} 202 203export function Item({children, label, onPress, ...rest}: ItemProps) { 204 const t = useTheme() 205 const {control} = React.useContext(Context) 206 const { 207 state: hovered, 208 onIn: onMouseEnter, 209 onOut: onMouseLeave, 210 } = useInteractionState() 211 const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() 212 213 return ( 214 <DropdownMenu.Item asChild> 215 <Pressable 216 {...rest} 217 className="radix-dropdown-item" 218 accessibilityHint="" 219 accessibilityLabel={label} 220 onPress={e => { 221 onPress(e) 222 223 /** 224 * Ported forward from Radix 225 * @see https://www.radix-ui.com/primitives/docs/components/dropdown-menu#item 226 */ 227 if (!e.defaultPrevented) { 228 control.close() 229 } 230 }} 231 onFocus={onFocus} 232 onBlur={onBlur} 233 // need `flatten` here for Radix compat 234 style={flatten([ 235 a.flex_row, 236 a.align_center, 237 a.gap_lg, 238 a.py_sm, 239 a.rounded_xs, 240 {minHeight: 32, paddingHorizontal: 10}, 241 web({outline: 0}), 242 (hovered || focused) && [ 243 web({outline: '0 !important'}), 244 t.name === 'light' 245 ? t.atoms.bg_contrast_25 246 : t.atoms.bg_contrast_50, 247 ], 248 ])} 249 {...web({ 250 onMouseEnter, 251 onMouseLeave, 252 })}> 253 {children} 254 </Pressable> 255 </DropdownMenu.Item> 256 ) 257} 258 259export function ItemText({children, style}: ItemTextProps) { 260 const t = useTheme() 261 return ( 262 <Text style={[a.flex_1, a.font_bold, t.atoms.text_contrast_high, style]}> 263 {children} 264 </Text> 265 ) 266} 267 268export function ItemIcon({icon: Comp, position = 'left'}: ItemIconProps) { 269 const t = useTheme() 270 return ( 271 <Comp 272 size="md" 273 fill={t.atoms.text_contrast_medium.color} 274 style={[ 275 position === 'left' && { 276 marginLeft: -2, 277 }, 278 position === 'right' && { 279 marginRight: -2, 280 marginLeft: 12, 281 }, 282 ]} 283 /> 284 ) 285} 286 287export function Group({children}: GroupProps) { 288 return children 289} 290 291export function Divider() { 292 const t = useTheme() 293 return ( 294 <DropdownMenu.Separator 295 style={flatten([ 296 a.my_xs, 297 t.atoms.bg_contrast_100, 298 { 299 height: 1, 300 }, 301 ])} 302 /> 303 ) 304}