11import defaultMdxComponents from 'fumadocs-ui/mdx' ;
22import type { MDXComponents } from 'mdx/types' ;
3+ import { Children , isValidElement , type ComponentProps , type ReactNode } from 'react' ;
34import { Info } from '@/components/info' ;
45import { Tip } from '@/components/tip' ;
56import { YouTube } from '@/components/youtube' ;
@@ -8,9 +9,45 @@ import { ScreenshotsGallery } from '@/components/screenshots-gallery';
89import { CopyBlock } from '@/app/components/copy-block' ;
910import { Pipeline , PipelineStep } from '@/components/pipeline' ;
1011
12+ const DefaultImg = defaultMdxComponents . img ;
13+
14+ // remark-image can emit fractional SVG dimensions, which next/image rejects
15+ const round = ( n ?: number | string ) => ( n == null ? n : Math . round ( Number ( n ) ) ) ;
16+
17+ const hasLink = ( children : ReactNode ) : boolean =>
18+ Children . toArray ( children ) . some (
19+ ( c ) => isValidElement < { href ?: string ; children ?: ReactNode } > ( c ) && ( c . props . href != null || hasLink ( c . props . children ) ) ,
20+ ) ;
21+
22+ // fumadocs' Heading wraps its children in an anchor link, so headings that are already links
23+ // would render a nested <a> (invalid HTML that breaks hydration); render those as plain headings
24+ function heading ( as : 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' ) {
25+ const Default = defaultMdxComponents [ as ] ;
26+ return function LinkSafeHeading ( props : ComponentProps < typeof as > ) {
27+ if ( ! hasLink ( props . children ) ) return < Default { ...props } /> ;
28+ const As = as ;
29+ return < As { ...props } className = { [ 'scroll-m-28' , props . className ] . filter ( Boolean ) . join ( ' ' ) } /> ;
30+ } ;
31+ }
32+
33+ const headings = {
34+ h1 : heading ( 'h1' ) ,
35+ h2 : heading ( 'h2' ) ,
36+ h3 : heading ( 'h3' ) ,
37+ h4 : heading ( 'h4' ) ,
38+ h5 : heading ( 'h5' ) ,
39+ h6 : heading ( 'h6' ) ,
40+ } ;
41+
42+ const Img = ( props : ComponentProps < typeof DefaultImg > ) => (
43+ < DefaultImg { ...props } width = { round ( props . width ) } height = { round ( props . height ) } />
44+ ) ;
45+
1146export function getMDXComponents ( components ?: MDXComponents ) : MDXComponents {
1247 return {
1348 ...defaultMdxComponents ,
49+ ...headings ,
50+ img : Img ,
1451 Info,
1552 Tip,
1653 YouTube,
0 commit comments