Changeset View
Changeset View
Standalone View
Standalone View
native/markdown/markdown-link.react.js
// @flow | // @flow | ||||
import invariant from 'invariant'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Text, Linking, Alert } from 'react-native'; | import { Text, Linking, Alert } from 'react-native'; | ||||
import { normalizeURL } from 'lib/utils/url-utils'; | import { normalizeURL } from 'lib/utils/url-utils'; | ||||
import { TextMessageMarkdownContext } from '../chat/text-message-markdown-context'; | |||||
import { MarkdownContext, type MarkdownContextType } from './markdown-context'; | import { MarkdownContext, type MarkdownContextType } from './markdown-context'; | ||||
function useDisplayLinkPrompt( | function useDisplayLinkPrompt( | ||||
inputURL: string, | inputURL: string, | ||||
markdownContext: ?MarkdownContextType, | markdownContext: MarkdownContextType, | ||||
messageKey: ?string, | |||||
) { | ) { | ||||
const setLinkModalActive = markdownContext?.setLinkModalActive; | const { setLinkModalActive } = markdownContext; | ||||
const onDismiss = React.useCallback(() => { | const onDismiss = React.useCallback(() => { | ||||
setLinkModalActive?.(false); | messageKey && setLinkModalActive({ [messageKey]: false }); | ||||
}, [setLinkModalActive]); | }, [setLinkModalActive, messageKey]); | ||||
const url = normalizeURL(inputURL); | const url = normalizeURL(inputURL); | ||||
const onConfirm = React.useCallback(() => { | const onConfirm = React.useCallback(() => { | ||||
onDismiss(); | onDismiss(); | ||||
Linking.openURL(url); | Linking.openURL(url); | ||||
}, [url, onDismiss]); | }, [url, onDismiss]); | ||||
let displayURL = url.substring(0, 64); | let displayURL = url.substring(0, 64); | ||||
if (url.length > displayURL.length) { | if (url.length > displayURL.length) { | ||||
displayURL += '…'; | displayURL += '…'; | ||||
} | } | ||||
return React.useCallback(() => { | return React.useCallback(() => { | ||||
setLinkModalActive && setLinkModalActive(true); | messageKey && setLinkModalActive({ [messageKey]: true }); | ||||
Alert.alert( | Alert.alert( | ||||
'External link', | 'External link', | ||||
`You sure you want to open this link?\n\n${displayURL}`, | `You sure you want to open this link?\n\n${displayURL}`, | ||||
[ | [ | ||||
{ text: 'Cancel', style: 'cancel', onPress: onDismiss }, | { text: 'Cancel', style: 'cancel', onPress: onDismiss }, | ||||
{ text: 'Open', onPress: onConfirm }, | { text: 'Open', onPress: onConfirm }, | ||||
], | ], | ||||
{ cancelable: true, onDismiss }, | { cancelable: true, onDismiss }, | ||||
); | ); | ||||
}, [setLinkModalActive, displayURL, onConfirm, onDismiss]); | }, [setLinkModalActive, messageKey, displayURL, onConfirm, onDismiss]); | ||||
} | } | ||||
type TextProps = React.ElementConfig<typeof Text>; | type TextProps = React.ElementConfig<typeof Text>; | ||||
type Props = { | type Props = { | ||||
+target: string, | +target: string, | ||||
+children: React.Node, | +children: React.Node, | ||||
...TextProps, | ...TextProps, | ||||
}; | }; | ||||
function MarkdownLink(props: Props): React.Node { | function MarkdownLink(props: Props): React.Node { | ||||
const { target, ...rest } = props; | const { target, ...rest } = props; | ||||
const markdownContext = React.useContext(MarkdownContext); | const markdownContext = React.useContext(MarkdownContext); | ||||
const onPressLink = useDisplayLinkPrompt(target, markdownContext); | invariant(markdownContext, 'MarkdownContext should be set'); | ||||
const textMessageMarkdownContext = React.useContext( | |||||
TextMessageMarkdownContext, | |||||
); | |||||
const messageKey = textMessageMarkdownContext?.messageKey; | |||||
const onPressLink = useDisplayLinkPrompt(target, markdownContext, messageKey); | |||||
return <Text onPress={onPressLink} {...rest} />; | return <Text onPress={onPressLink} {...rest} />; | ||||
} | } | ||||
export default MarkdownLink; | export default MarkdownLink; |