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 profile-init 330 lines 8.6 kB view raw
1import React, {ComponentProps, memo, useMemo} from 'react' 2import { 3 Linking, 4 GestureResponderEvent, 5 Platform, 6 StyleProp, 7 TextStyle, 8 TextProps, 9 View, 10 ViewStyle, 11 Pressable, 12 TouchableWithoutFeedback, 13 TouchableOpacity, 14} from 'react-native' 15import { 16 useLinkProps, 17 useNavigation, 18 StackActions, 19} from '@react-navigation/native' 20import {Text} from './text/Text' 21import {TypographyVariant} from 'lib/ThemeContext' 22import {NavigationProp} from 'lib/routes/types' 23import {router} from '../../../routes' 24import {useStores, RootStoreModel} from 'state/index' 25import { 26 convertBskyAppUrlIfNeeded, 27 isExternalUrl, 28 linkRequiresWarning, 29} from 'lib/strings/url-helpers' 30import {isAndroid} from 'platform/detection' 31import {sanitizeUrl} from '@braintree/sanitize-url' 32import {PressableWithHover} from './PressableWithHover' 33import FixedTouchableHighlight from '../pager/FixedTouchableHighlight' 34import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 35 36type Event = 37 | React.MouseEvent<HTMLAnchorElement, MouseEvent> 38 | GestureResponderEvent 39 40interface Props extends ComponentProps<typeof TouchableOpacity> { 41 testID?: string 42 style?: StyleProp<ViewStyle> 43 href?: string 44 title?: string 45 children?: React.ReactNode 46 hoverStyle?: StyleProp<ViewStyle> 47 noFeedback?: boolean 48 asAnchor?: boolean 49 anchorNoUnderline?: boolean 50} 51 52export const Link = memo(function Link({ 53 testID, 54 style, 55 href, 56 title, 57 children, 58 noFeedback, 59 asAnchor, 60 accessible, 61 anchorNoUnderline, 62 ...props 63}: Props) { 64 const store = useStores() 65 const navigation = useNavigation<NavigationProp>() 66 const anchorHref = asAnchor ? sanitizeUrl(href) : undefined 67 68 const onPress = React.useCallback( 69 (e?: Event) => { 70 if (typeof href === 'string') { 71 return onPressInner(store, navigation, sanitizeUrl(href), e) 72 } 73 }, 74 [store, navigation, href], 75 ) 76 77 if (noFeedback) { 78 if (isAndroid) { 79 // workaround for Android not working well with left/right swipe gestures and TouchableWithoutFeedback 80 // https://github.com/callstack/react-native-pager-view/issues/424 81 return ( 82 <FixedTouchableHighlight 83 testID={testID} 84 onPress={onPress} 85 // @ts-ignore web only -prf 86 href={asAnchor ? sanitizeUrl(href) : undefined} 87 accessible={accessible} 88 accessibilityRole="link" 89 {...props}> 90 <View style={style}> 91 {children ? children : <Text>{title || 'link'}</Text>} 92 </View> 93 </FixedTouchableHighlight> 94 ) 95 } 96 return ( 97 <TouchableWithoutFeedback 98 testID={testID} 99 onPress={onPress} 100 accessible={accessible} 101 accessibilityRole="link" 102 {...props}> 103 {/* @ts-ignore web only -prf */} 104 <View style={style} href={anchorHref}> 105 {children ? children : <Text>{title || 'link'}</Text>} 106 </View> 107 </TouchableWithoutFeedback> 108 ) 109 } 110 111 if (anchorNoUnderline) { 112 // @ts-ignore web only -prf 113 props.dataSet = props.dataSet || {} 114 // @ts-ignore web only -prf 115 props.dataSet.noUnderline = 1 116 } 117 118 if (title && !props.accessibilityLabel) { 119 props.accessibilityLabel = title 120 } 121 122 const Com = props.hoverStyle ? PressableWithHover : Pressable 123 return ( 124 <Com 125 testID={testID} 126 style={style} 127 onPress={onPress} 128 accessible={accessible} 129 accessibilityRole="link" 130 // @ts-ignore web only -prf 131 href={anchorHref} 132 {...props}> 133 {children ? children : <Text>{title || 'link'}</Text>} 134 </Com> 135 ) 136}) 137 138export const TextLink = memo(function TextLink({ 139 testID, 140 type = 'md', 141 style, 142 href, 143 text, 144 numberOfLines, 145 lineHeight, 146 dataSet, 147 title, 148 onPress, 149 warnOnMismatchingLabel, 150 ...orgProps 151}: { 152 testID?: string 153 type?: TypographyVariant 154 style?: StyleProp<TextStyle> 155 href: string 156 text: string | JSX.Element | React.ReactNode 157 numberOfLines?: number 158 lineHeight?: number 159 dataSet?: any 160 title?: string 161 warnOnMismatchingLabel?: boolean 162} & TextProps) { 163 const {...props} = useLinkProps({to: sanitizeUrl(href)}) 164 const store = useStores() 165 const navigation = useNavigation<NavigationProp>() 166 167 if (warnOnMismatchingLabel && typeof text !== 'string') { 168 console.error('Unable to detect mismatching label') 169 } 170 171 props.onPress = React.useCallback( 172 (e?: Event) => { 173 const requiresWarning = 174 warnOnMismatchingLabel && 175 linkRequiresWarning(href, typeof text === 'string' ? text : '') 176 if (requiresWarning) { 177 e?.preventDefault?.() 178 store.shell.openModal({ 179 name: 'link-warning', 180 text: typeof text === 'string' ? text : '', 181 href, 182 }) 183 } 184 if (onPress) { 185 e?.preventDefault?.() 186 // @ts-ignore function signature differs by platform -prf 187 return onPress() 188 } 189 return onPressInner(store, navigation, sanitizeUrl(href), e) 190 }, 191 [onPress, store, navigation, href, text, warnOnMismatchingLabel], 192 ) 193 const hrefAttrs = useMemo(() => { 194 const isExternal = isExternalUrl(href) 195 if (isExternal) { 196 return { 197 target: '_blank', 198 // rel: 'noopener noreferrer', 199 } 200 } 201 return {} 202 }, [href]) 203 204 return ( 205 <Text 206 testID={testID} 207 type={type} 208 style={style} 209 numberOfLines={numberOfLines} 210 lineHeight={lineHeight} 211 dataSet={dataSet} 212 title={title} 213 // @ts-ignore web only -prf 214 hrefAttrs={hrefAttrs} // hack to get open in new tab to work on safari. without this, safari will open in a new window 215 {...props} 216 {...orgProps}> 217 {text} 218 </Text> 219 ) 220}) 221 222/** 223 * Only acts as a link on desktop web 224 */ 225interface DesktopWebTextLinkProps extends TextProps { 226 testID?: string 227 type?: TypographyVariant 228 style?: StyleProp<TextStyle> 229 href: string 230 text: string | JSX.Element 231 numberOfLines?: number 232 lineHeight?: number 233 accessible?: boolean 234 accessibilityLabel?: string 235 accessibilityHint?: string 236 title?: string 237} 238export const DesktopWebTextLink = memo(function DesktopWebTextLink({ 239 testID, 240 type = 'md', 241 style, 242 href, 243 text, 244 numberOfLines, 245 lineHeight, 246 ...props 247}: DesktopWebTextLinkProps) { 248 const {isDesktop} = useWebMediaQueries() 249 250 if (isDesktop) { 251 return ( 252 <TextLink 253 testID={testID} 254 type={type} 255 style={style} 256 href={href} 257 text={text} 258 numberOfLines={numberOfLines} 259 lineHeight={lineHeight} 260 title={props.title} 261 {...props} 262 /> 263 ) 264 } 265 return ( 266 <Text 267 testID={testID} 268 type={type} 269 style={style} 270 numberOfLines={numberOfLines} 271 lineHeight={lineHeight} 272 title={props.title} 273 {...props}> 274 {text} 275 </Text> 276 ) 277}) 278 279// NOTE 280// we can't use the onPress given by useLinkProps because it will 281// match most paths to the HomeTab routes while we actually want to 282// preserve the tab the app is currently in 283// 284// we also have some additional behaviors - closing the current modal, 285// converting bsky urls, and opening http/s links in the system browser 286// 287// this method copies from the onPress implementation but adds our 288// needed customizations 289// -prf 290function onPressInner( 291 store: RootStoreModel, 292 navigation: NavigationProp, 293 href: string, 294 e?: Event, 295) { 296 let shouldHandle = false 297 const isLeftClick = 298 // @ts-ignore Web only -prf 299 Platform.OS === 'web' && (e.button == null || e.button === 0) 300 // @ts-ignore Web only -prf 301 const isMiddleClick = Platform.OS === 'web' && e.button === 1 302 const isMetaKey = 303 // @ts-ignore Web only -prf 304 Platform.OS === 'web' && (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) 305 const newTab = isMetaKey || isMiddleClick 306 307 if (Platform.OS !== 'web' || !e) { 308 shouldHandle = e ? !e.defaultPrevented : true 309 } else if ( 310 !e.defaultPrevented && // onPress prevented default 311 (isLeftClick || isMiddleClick) && // ignore everything but left and middle clicks 312 // @ts-ignore Web only -prf 313 [undefined, null, '', 'self'].includes(e.currentTarget?.target) // let browser handle "target=_blank" etc. 314 ) { 315 e.preventDefault() 316 shouldHandle = true 317 } 318 319 if (shouldHandle) { 320 href = convertBskyAppUrlIfNeeded(href) 321 if (newTab || href.startsWith('http') || href.startsWith('mailto')) { 322 Linking.openURL(href) 323 } else { 324 store.shell.closeModal() // close any active modals 325 326 // @ts-ignore we're not able to type check on this one -prf 327 navigation.dispatch(StackActions.push(...router.matchPath(href))) 328 } 329 } 330}