Skip to content

Commit

Permalink
[v3] fix removeLinks when input node is link (#2431)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dimitri POSTOLOV authored Oct 11, 2023
1 parent e2f4505 commit 31c2ee7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-rivers-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'nextra-theme-docs': patch
---

fix `removeLinks` when input node is link
23 changes: 2 additions & 21 deletions packages/nextra-theme-docs/src/components/toc.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import cn from 'clsx'
import type { Heading } from 'nextra'
import type { ReactElement } from 'react'
import { Children, cloneElement, useEffect, useRef } from 'react'
import { useEffect, useRef } from 'react'
import scrollIntoView from 'scroll-into-view-if-needed'
import { useActiveAnchor, useThemeConfig } from '../contexts'
import { renderComponent } from '../utils'
import { removeLinks } from '../utils/remove-links'
import { Anchor } from './anchor'
import { BackToTop } from './back-to-top'

Expand All @@ -18,26 +19,6 @@ const linkClassName = cn(
'contrast-more:_text-gray-800 contrast-more:dark:_text-gray-50'
)

type TOCElement = ReactElement | string

function isLink(node: TOCElement): node is ReactElement {
return typeof node !== 'string' && !!node.props.href
}

function removeLinks(node: TOCElement): TOCElement[] {
return Children.map(node, child => {
if (isLink(child)) {
child = child.props.children
}

return typeof child === 'string'
? child
: cloneElement(child, {
children: removeLinks(child.props.children)
})
})
}

export function TOC({ toc, filePath }: TOCProps): ReactElement {
const activeAnchor = useActiveAnchor()
const tocRef = useRef<HTMLDivElement>(null)
Expand Down
42 changes: 42 additions & 0 deletions packages/nextra-theme-docs/src/utils/remove-links.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { removeLinks } from './remove-links'

describe('removeLinks()', () => {
it('should return string', () => {
expect(removeLinks('foo')).toBe('foo')
})
it('should remove link inside fragment', () => {
const node = (
<>
foo
<code>
<a href="#">bar</a>
</code>
</>
)
expect(removeLinks(node)).toMatchInlineSnapshot(`
[
<React.Fragment>
foo
<code>
bar
</code>
</React.Fragment>,
]
`)
})
it('should remove wrapper link', () => {
const node = (
<a href="#">
foo<code>bar</code>
</a>
)
expect(removeLinks(node)).toMatchInlineSnapshot(`
[
"foo",
<code>
bar
</code>,
]
`)
})
})
32 changes: 32 additions & 0 deletions packages/nextra-theme-docs/src/utils/remove-links.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { ReactElement } from 'react'
import { Children, cloneElement } from 'react'

type TOCElement = ReactElement | string

function isLink(node: TOCElement): node is ReactElement {
return typeof node !== 'string' && !!node.props.href
}

export function removeLinks(node: TOCElement): TOCElement[] | string {
if (typeof node === 'string') {
return node
}
// @ts-expect-error fixme
return Children.map(node, child => {
if (isLink(child)) {
child = child.props.children
}

if (typeof child === 'string') {
return child
}

if (Array.isArray(child)) {
return removeLinks(child)
}

const children = removeLinks(child.props.children)

return cloneElement(child, { children })
})
}

0 comments on commit 31c2ee7

Please sign in to comment.