Merge branch 'main' into stevenh/fix-empty-href

This commit is contained in:
Steven H
2025-06-02 14:23:26 +01:00
committed by GitHub
4 changed files with 69 additions and 15 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
fix nested a tag causing hydration error
@@ -4,7 +4,7 @@ import {
SiteInsightsLinkPosition,
} from '@gitbook/api';
import { Link } from '@/components/primitives';
import { LinkBox, LinkOverlay } from '@/components/primitives';
import { Image } from '@/components/utils';
import { resolveContentRef } from '@/lib/references';
import { type ClassValue, tcls } from '@/lib/tailwind';
@@ -44,7 +44,6 @@ export async function RecordCard(
<div
className={tcls(
'grid-area-1-1',
'z-0',
'relative',
'grid',
'bg-tint-base',
@@ -151,7 +150,6 @@ export async function RecordCard(
'rounded-md',
'straight-corners:rounded-none',
'dark:shadow-transparent',
'z-0',
'before:pointer-events-none',
'before:grid-area-1-1',
@@ -167,19 +165,22 @@ export async function RecordCard(
if (target && targetRef) {
return (
<Link
href={target.href}
className={tcls(style, 'hover:before:ring-tint-12/5')}
insights={{
type: 'link_click',
link: {
target: targetRef,
position: SiteInsightsLinkPosition.Content,
},
}}
>
// We don't use `Link` directly here because we could end up in a situation where
// a link is rendered inside a link, which is not allowed in HTML.
// It causes an hydration error in React.
<LinkBox href={target.href} className={tcls(style, 'hover:before:ring-tint-12/5')}>
<LinkOverlay
href={target.href}
insights={{
type: 'link_click',
link: {
target: targetRef,
position: SiteInsightsLinkPosition.Content,
},
}}
/>
{body}
</Link>
</LinkBox>
);
}
@@ -148,6 +148,13 @@
width: 100%;
}
}
.elevate-link {
& a[href]:not(.link-overlay) {
position: relative;
z-index: 20;
}
}
}
html {
@@ -3,6 +3,7 @@
import NextLink, { type LinkProps as NextLinkProps } from 'next/link';
import React from 'react';
import { tcls } from '@/lib/tailwind';
import { type TrackEventInput, useTrackEvent } from '../Insights';
// Props from Next, which includes NextLinkProps and all the things anchor elements support.
@@ -75,6 +76,46 @@ export const Link = React.forwardRef(function Link(
);
});
/**
* A box used to contain a link overlay.
* It is used to create a clickable area that can contain other elements.
*/
export const LinkBox = React.forwardRef(function LinkBox(
props: React.BaseHTMLAttributes<HTMLDivElement>,
ref: React.Ref<HTMLDivElement>
) {
const { children, className, ...domProps } = props;
return (
<div ref={ref} {...domProps} className={tcls('elevate-link relative', className)}>
{children}
</div>
);
});
/**
* A link overlay that can be used to create a clickable area on top of other elements.
* It is used to create a link that covers the entire area of the element without encapsulating it in a link tag.
* This is useful to avoid nesting links inside links.
*/
export const LinkOverlay = React.forwardRef(function LinkOverlay(
props: LinkProps,
ref: React.Ref<HTMLAnchorElement>
) {
const { children, className, ...domProps } = props;
return (
<Link
ref={ref}
{...domProps}
className={tcls(
'link-overlay static before:absolute before:top-0 before:left-0 before:z-10 before:h-full before:w-full',
className
)}
>
{children}
</Link>
);
});
/**
* Check if a link is external, compared to an origin.
*/