diff --git a/__tests__/lib/strings/url-helpers.test.ts b/__tests__/lib/strings/url-helpers.test.ts index 0b1b750281..339556a02d 100644 --- a/__tests__/lib/strings/url-helpers.test.ts +++ b/__tests__/lib/strings/url-helpers.test.ts @@ -1,10 +1,11 @@ import {describe, expect, it} from '@jest/globals' +// co-located with LinkBox.tsx so we can lazy load PSL +import {splitApexDomain} from '../../../src/components/dialogs/LinkWarning/LinkBox' import { isPossiblyAUrl, isTrustedUrl, linkRequiresWarning, - splitApexDomain, } from '../../../src/lib/strings/url-helpers' describe('linkRequiresWarning', () => { diff --git a/src/components/dialogs/LinkWarning/LinkBox.tsx b/src/components/dialogs/LinkWarning/LinkBox.tsx new file mode 100644 index 0000000000..3814eaa06d --- /dev/null +++ b/src/components/dialogs/LinkWarning/LinkBox.tsx @@ -0,0 +1,54 @@ +import {useMemo} from 'react' +import {View} from 'react-native' +import psl from 'psl' + +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' + +export function splitApexDomain(hostname: string): [string, string] { + const hostnamep = psl.parse(hostname) + if (hostnamep.error || !hostnamep.listed || !hostnamep.domain) { + return ['', hostname] + } + return [ + hostnamep.subdomain ? `${hostnamep.subdomain}.` : '', + hostnamep.domain, + ] +} + +export default function LinkBox({href}: {href: string}) { + const t = useTheme() + const [scheme, hostname, rest] = useMemo(() => { + try { + const urlp = new URL(href) + const [subdomain, apexdomain] = splitApexDomain(urlp.hostname) + return [ + urlp.protocol + '//' + subdomain, + apexdomain, + urlp.pathname.replace(/\/$/, '') + urlp.search + urlp.hash, + ] + } catch { + return ['', href, ''] + } + }, [href]) + return ( + + + {scheme} + + {hostname} + + {rest} + + + ) +} diff --git a/src/components/dialogs/LinkWarning.tsx b/src/components/dialogs/LinkWarning/index.tsx similarity index 87% rename from src/components/dialogs/LinkWarning.tsx rename to src/components/dialogs/LinkWarning/index.tsx index 181d411ce4..e78eece22c 100644 --- a/src/components/dialogs/LinkWarning.tsx +++ b/src/components/dialogs/LinkWarning/index.tsx @@ -1,16 +1,18 @@ -import {useCallback, useMemo} from 'react' +import {lazy, Suspense, useCallback, useMemo} 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 {isPossiblyAUrl} from '#/lib/strings/url-helpers' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import {Button, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {Text} from '#/components/Typography' -import {useGlobalDialogsControlContext} from './Context' +import {useGlobalDialogsControlContext} from '../Context' + +const LinkBox = lazy(() => import('./LinkBox.tsx')) export function LinkWarningDialog() { const {linkWarningDialogControl} = useGlobalDialogsControlContext() @@ -93,7 +95,11 @@ function LinkWarningDialogInner({ This link is taking you to the following website: - {link && } + {link && ( + }> + + + )} {potentiallyMisleading && ( @@ -112,7 +118,6 @@ function LinkWarningDialogInner({ accessibilityHint={_(msg`Opens link ${link?.href ?? ''}`)} onPress={onPressVisit} size="large" - variant="solid" color={potentiallyMisleading ? 'secondary_inverted' : 'primary'}> {link?.share ? ( @@ -139,15 +144,19 @@ function LinkWarningDialogInner({ ) } -function LinkBox({href}: {href: string}) { +/** + * Same as LinkBox but does not split the apex domain from the subdomain. + * This shows while we lazy load the LinkBox component, so that we can + * split `psl` out of the main bundle. + */ +function FallbackLinkBox({href}: {href: string}) { const t = useTheme() const [scheme, hostname, rest] = useMemo(() => { try { const urlp = new URL(href) - const [subdomain, apexdomain] = splitApexDomain(urlp.hostname) return [ - urlp.protocol + '//' + subdomain, - apexdomain, + urlp.protocol + '//', + urlp.hostname, urlp.pathname.replace(/\/$/, '') + urlp.search + urlp.hash, ] } catch { diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts index 6088e28065..b955587f94 100644 --- a/src/lib/strings/url-helpers.ts +++ b/src/lib/strings/url-helpers.ts @@ -1,5 +1,4 @@ import {AtUri} from '@atproto/api' -import psl from 'psl' import TLDs from 'tlds' import {BSKY_SERVICE} from '#/lib/constants' @@ -310,17 +309,6 @@ export function isPossiblyAUrl(str: string): boolean { return isValidDomain(firstWord) } -export function splitApexDomain(hostname: string): [string, string] { - const hostnamep = psl.parse(hostname) - if (hostnamep.error || !hostnamep.listed || !hostnamep.domain) { - return ['', hostname] - } - return [ - hostnamep.subdomain ? `${hostnamep.subdomain}.` : '', - hostnamep.domain, - ] -} - export function createBskyAppAbsoluteUrl(path: string): string { const sanitizedPath = path.replace(BSKY_APP_HOST, '').replace(/^\/+/, '') return `${BSKY_APP_HOST.replace(/\/$/, '')}/${sanitizedPath}`