diff --git a/src/components/Markdown/Markdown.test.tsx b/src/components/Markdown/Markdown.test.tsx
index d52df16d..6f4e887e 100644
--- a/src/components/Markdown/Markdown.test.tsx
+++ b/src/components/Markdown/Markdown.test.tsx
@@ -80,6 +80,14 @@ describe('Markdown', () => {
expect(getByRole('link').getAttribute('href')).toBe('https://hyperparam.app')
})
+ it('renders a partial link', () => {
+ const text = 'Check out [Hyp](https://hyper'
+ const { getByText, queryByText } = render()
+ expect(getByText('Hyp')).toBeDefined()
+ expect(queryByText('hyper')).toBeNull()
+ expect(getByText('Hyp').tagName).toBe('A')
+ })
+
it('renders multiple links in one line', () => {
const text = 'Check out [Hyp](https://hyperparam.app) on [GitHub](https://github.com/hyparam).'
const { getAllByRole, getByText } = render()
diff --git a/src/components/Markdown/Markdown.tsx b/src/components/Markdown/Markdown.tsx
index f42564f5..024fc991 100644
--- a/src/components/Markdown/Markdown.tsx
+++ b/src/components/Markdown/Markdown.tsx
@@ -302,7 +302,10 @@ function parseInlineRecursive(text: string, stop?: string): [Token[], number] {
i++ // skip '('
const endParen = text.indexOf(')', i)
if (endParen === -1) {
- tokens.push({ type: 'text', content: text.slice(start, i) })
+ // No closing ")": assume in-flight href
+ const href = text.slice(i).trim()
+ i = text.length // consume to EOI so loop terminates
+ tokens.push({ type: 'link', href, children: linkTextTokens })
continue
}
const href = text.slice(i, endParen).trim()