diff --git a/src/components/Link.tsx b/src/components/Link.tsx
index 447833a239..f49795750f 100644
--- a/src/components/Link.tsx
+++ b/src/components/Link.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {useCallback, useState} from 'react'
import {
GestureResponderEvent,
Pressable,
@@ -20,10 +20,11 @@ import {
} from '#/lib/strings/url-helpers'
import {isNative, isWeb} from '#/platform/detection'
import {shouldClickOpenNewTab} from '#/platform/urls'
-import {useModalControls} from '#/state/modals'
import {useOpenLink} from '#/state/preferences/in-app-browser'
+import {useCloseAllActiveElements} from '#/state/util'
import {atoms as a, flatten, TextStyleProp, useTheme, web} from '#/alf'
import {Button, ButtonProps} from '#/components/Button'
+import {useDialogControl} from '#/components/Dialog'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text, TextProps} from '#/components/Typography'
import {router} from '#/routes'
@@ -87,10 +88,20 @@ export function useLink({
typeof to === 'string' ? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) : to,
})
const isExternal = isExternalUrl(href)
- const {openModal, closeModal} = useModalControls()
const openLink = useOpenLink()
+ const dismissEverything = useCloseAllActiveElements()
+ const [_warningMode, setWarningMode] = useState<'open' | 'share'>('open')
+ const linkWarningControl = useDialogControl()
- const onPress = React.useCallback(
+ const showWarningDialog = useCallback(
+ (mode: 'open' | 'share') => {
+ setWarningMode(mode)
+ linkWarningControl.open()
+ },
+ [linkWarningControl],
+ )
+
+ const onPress = useCallback(
(e: GestureResponderEvent) => {
const exitEarlyIfFalse = outerOnPress?.(e)
@@ -108,11 +119,7 @@ export function useLink({
}
if (requiresWarning) {
- openModal({
- name: 'link-warning',
- text: displayText,
- href: href,
- })
+ showWarningDialog('open')
} else {
if (isExternal) {
openLink(href)
@@ -128,7 +135,7 @@ export function useLink({
) {
openLink(href)
} else {
- closeModal() // close any active modals
+ dismissEverything() // close any active dialogs
if (action === 'push') {
navigation.dispatch(StackActions.push(...router.matchPath(href)))
@@ -152,15 +159,15 @@ export function useLink({
displayText,
isExternal,
href,
- openModal,
openLink,
- closeModal,
action,
navigation,
+ showWarningDialog,
+ dismissEverything,
],
)
- const handleLongPress = React.useCallback(() => {
+ const handleLongPress = useCallback(() => {
const requiresWarning = Boolean(
!disableMismatchWarning &&
displayText &&
@@ -169,16 +176,11 @@ export function useLink({
)
if (requiresWarning) {
- openModal({
- name: 'link-warning',
- text: displayText,
- href: href,
- share: true,
- })
+ showWarningDialog('share')
} else {
shareUrl(href)
}
- }, [disableMismatchWarning, displayText, href, isExternal, openModal])
+ }, [disableMismatchWarning, displayText, href, isExternal, showWarningDialog])
const onLongPress =
isNative && isExternal && shareOnLongPress ? handleLongPress : undefined
diff --git a/src/components/dialogs/LinkWarningDialog.tsx b/src/components/dialogs/LinkWarningDialog.tsx
new file mode 100644
index 0000000000..6e3c7c5aa6
--- /dev/null
+++ b/src/components/dialogs/LinkWarningDialog.tsx
@@ -0,0 +1,152 @@
+import React from 'react'
+import {View} from 'react-native'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useOpenLink} from '#/lib/hooks/useOpenLink'
+import {shareUrl} from '#/lib/sharing'
+import {isPossiblyAUrl, splitApexDomain} from '#/lib/strings/url-helpers'
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+import * as Dialog from '#/components/Dialog'
+import {Text} from '#/components/Typography'
+
+export function LinkWarningDialog({
+ control,
+ linkText,
+ linkHref,
+ mode = 'open',
+}: {
+ control: Dialog.DialogControlProps
+ linkText: string
+ linkHref: string
+ mode?: 'open' | 'share'
+}) {
+ return (
+
+
+
+
+ )
+}
+
+function DialogInner({
+ linkText,
+ linkHref,
+ mode,
+}: {
+ linkText: string
+ linkHref: string
+ mode: 'open' | 'share'
+}) {
+ const control = Dialog.useDialogContext()
+ const {_} = useLingui()
+ const potentiallyMisleading = isPossiblyAUrl(linkText)
+ const openLink = useOpenLink()
+
+ const share = mode === 'share'
+
+ const onPressVisit = () => {
+ control.close(() => {
+ if (share) {
+ shareUrl(linkHref)
+ } else {
+ openLink(linkHref)
+ }
+ })
+ }
+ return (
+
+
+ {potentiallyMisleading ? (
+ <>
+ {/* */}
+
+ Potentially Misleading Link
+
+ >
+ ) : (
+
+ Leaving Bluesky
+
+ )}
+
+
+
+
+ This link is taking you to the following website:
+
+
+
+
+ {potentiallyMisleading && (
+
+ Make sure this is where you intend to go!
+
+ )}
+
+
+
+
+
+
+
+ )
+}
+
+function LinkBox({href}: {href: string}) {
+ const t = useTheme()
+ const [scheme, hostname, rest] = React.useMemo(() => {
+ try {
+ const urlp = new URL(href)
+ const [subdomain, apexdomain] = splitApexDomain(urlp.hostname)
+ return [
+ urlp.protocol + '//' + subdomain,
+ apexdomain,
+ urlp.pathname + urlp.search + urlp.hash,
+ ]
+ } catch {
+ return ['', href, '']
+ }
+ }, [href])
+ return (
+
+
+ {scheme}
+ {hostname}
+ {rest}
+
+
+ )
+}