Skip to content

Commit

Permalink
fix: FernExternalLink opens samesite without _blank (#866)
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity authored May 15, 2024
1 parent e6bf566 commit 9f6eab6
Showing 1 changed file with 47 additions and 12 deletions.
59 changes: 47 additions & 12 deletions packages/ui/app/src/components/FernLink.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { ExternalLinkIcon } from "@radix-ui/react-icons";
import Link from "next/link";
import { ReactElement, type ComponentProps } from "react";
import { ReactElement, useEffect, useState, type ComponentProps } from "react";
import { format, parse, resolve, type UrlObject } from "url";
import { useDocsContext } from "../contexts/docs-context/useDocsContext";
import { useNavigationContext } from "../contexts/navigation-context";

interface FernLinkProps extends ComponentProps<typeof Link> {
showExternalLinkIcon?: boolean;
}

export function FernLink({ showExternalLinkIcon, ...props }: FernLinkProps): ReactElement {
export function FernLink({ showExternalLinkIcon = false, ...props }: FernLinkProps): ReactElement {
const url = toUrlObject(props.href);
const isExternalUrl = checkIsExternalUrl(url);

Expand All @@ -19,12 +20,11 @@ export function FernLink({ showExternalLinkIcon, ...props }: FernLinkProps): Rea
return <FernRelativeLink {...props} />;
}

return (
<Link {...props} target={isExternalUrl ? "_blank" : props.target}>
{props.children}
{isExternalUrl && showExternalLinkIcon && <ExternalLinkIcon className="external-link-icon" />}
</Link>
);
if (isExternalUrl) {
return <FernExternalLink {...props} showExternalLinkIcon={showExternalLinkIcon} url={url} />;
}

return <Link {...props} />;
}

function FernRelativeLink(props: ComponentProps<typeof Link>) {
Expand All @@ -33,6 +33,45 @@ function FernRelativeLink(props: ComponentProps<typeof Link>) {
return <Link {...props} href={href} />;
}

interface FernExternalLinkProps extends Omit<ComponentProps<"a">, "href"> {
showExternalLinkIcon: boolean;
url: UrlObject;
}

function FernExternalLink({ showExternalLinkIcon, url, ...props }: FernExternalLinkProps) {
const { domain } = useDocsContext();
const [host, setHost] = useState<string>(domain);
useEffect(() => {
if (typeof window !== "undefined") {
setHost(window.location.host);
}
}, []);

// if the link is to a different domain, always open in a new tab
// TODO: if the link is to the same domain, we should check if the page is a fern page, and if so, use the Link component to leverage client-side navigation
const isSameSite = host === url.host;
return (
// eslint-disable-next-line react/jsx-no-target-blank
<a
{...props}
target={isSameSite || props.target != null ? props.target : "_blank"}
rel={
isSameSite && props.target !== "_blank"
? props.rel
: props.rel == null
? "noreferrer"
: props.rel.includes("noreferrer")
? props.rel
: `${props.rel} noreferrer`
}
href={formatUrlString(url)}
>
{props.children}
{!isSameSite && showExternalLinkIcon && <ExternalLinkIcon className="external-link-icon" />}
</a>
);
}

export function toUrlObject(url: string | UrlObject): UrlObject {
if (url == null) {
return {};
Expand Down Expand Up @@ -61,10 +100,6 @@ export function checkIsExternalUrl(url: UrlObject): boolean {
}

export function checkIsRelativeUrl(url: UrlObject): boolean {
if (checkIsExternalUrl(url)) {
return false;
}

if (url.href == null) {
return true;
}
Expand Down

0 comments on commit 9f6eab6

Please sign in to comment.