Skip to content

Commit 04f137e

Browse files
birkskyumbrenelz
andauthored
fix(solid-router): allow creating link for client-side-routing in SVG (#5667)
* add test * fix svg links in solid router --------- Co-authored-by: Brenley Dueck <[email protected]>
1 parent 1d91138 commit 04f137e

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

e2e/solid-router/basic/src/main.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Link,
66
Outlet,
77
RouterProvider,
8+
createLink,
89
createRootRoute,
910
createRoute,
1011
createRouter,
@@ -28,6 +29,7 @@ const rootRoute = createRootRoute({
2829
})
2930

3031
function RootComponent() {
32+
const SvgLink = createLink('svg')
3133
return (
3234
<>
3335
<HeadContent />
@@ -71,7 +73,23 @@ function RootComponent() {
7173
}}
7274
>
7375
This Route Does Not Exist
74-
</Link>
76+
</Link>{' '}
77+
<div class="flex items-center">
78+
<svg width="20" height="20" viewBox="0 0 20 20" role="img">
79+
<title id="rectTitle">Link in SVG</title>
80+
<SvgLink to="/posts" aria-label="Open posts from SVG">
81+
<rect
82+
x="0"
83+
y="0"
84+
width="20"
85+
height="20"
86+
rx="4"
87+
fill="blue"
88+
stroke-width="2"
89+
/>
90+
</SvgLink>
91+
</svg>
92+
</div>
7593
</div>
7694
<Outlet />
7795
<TanStackRouterDevtools position="bottom-right" />

e2e/solid-router/basic/tests/app.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
import { expect, test } from '@playwright/test'
2+
import { getTestServerPort } from '@tanstack/router-e2e-utils'
3+
import packageJson from '../package.json' with { type: 'json' }
4+
5+
const PORT = await getTestServerPort(packageJson.name)
26

37
test.beforeEach(async ({ page }) => {
48
await page.goto('/')
@@ -45,3 +49,16 @@ test('Navigating to a post page with viewTransition types', async ({
4549
await page.getByRole('link', { name: 'sunt aut facere repe' }).click()
4650
await expect(page.getByRole('heading')).toContainText('sunt aut facere')
4751
})
52+
53+
test('Link in SVG does not trigger a full page reload', async ({ page }) => {
54+
let fullPageLoad = false
55+
page.on('domcontentloaded', () => {
56+
fullPageLoad = true
57+
})
58+
59+
await page.getByRole('link', { name: 'Open posts from SVG' }).click()
60+
const url = `http://localhost:${PORT}/posts`
61+
await page.waitForURL(url)
62+
63+
expect(fullPageLoad).toBeFalsy()
64+
})

packages/solid-router/src/link.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ export function useLinkProps<
281281
// The click handler
282282
const handleClick = (e: MouseEvent) => {
283283
// Check actual element's target attribute as fallback
284-
const elementTarget = (e.currentTarget as HTMLAnchorElement).target
284+
const elementTarget = (
285+
e.currentTarget as HTMLAnchorElement | SVGAElement
286+
).getAttribute('target')
285287
const effectiveTarget =
286288
local.target !== undefined ? local.target : elementTarget
287289

@@ -587,6 +589,15 @@ export const Link: LinkComponent<'a'> = (props) => {
587589
return ch satisfies Solid.JSX.Element
588590
})
589591

592+
if (local._asChild === 'svg') {
593+
const [_, svgLinkProps] = Solid.splitProps(linkProps, ['class'])
594+
return (
595+
<svg>
596+
<a {...svgLinkProps}>{children()}</a>
597+
</svg>
598+
)
599+
}
600+
590601
return (
591602
<Dynamic component={local._asChild ? local._asChild : 'a'} {...linkProps}>
592603
{children()}

0 commit comments

Comments
 (0)