Skip to content

Commit

Permalink
fix: persisting the 'disabled' prop for custom link elements using `c…
Browse files Browse the repository at this point in the history
…reateLink` (#1544)

* fix(react-router): do not remove the disabled prop for `_asChild` links

* refactor(react-router): useLinkProps always returns a `disabled` boolean

* test(react-router): make sure this works as exptected

* test(react-router): tests to include other props

* test: use queryByText
  • Loading branch information
SeanCassiere authored May 1, 2024
1 parent 7507443 commit fbf1d02
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/react-router/src/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ export function useLinkProps<
onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
disabled: !!disabled,
target,
...(Object.keys(resolvedStyle).length && { style: resolvedStyle }),
...(resolvedClassName && { className: resolvedClassName }),
Expand Down Expand Up @@ -810,6 +811,12 @@ export const Link: LinkComponent<'a'> = React.forwardRef((props: any, ref) => {
})
: rest.children

if (typeof _asChild === 'undefined') {
// the ReturnType of useLinkProps returns the correct type for a <a> element, not a general component that has a delete prop
// @ts-expect-error
delete linkProps.disabled
}

return React.createElement(
_asChild ? _asChild : 'a',
{
Expand Down
103 changes: 103 additions & 0 deletions packages/react-router/tests/link.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react'
import { describe, it, expect, afterEach } from 'vitest'
import { render, cleanup } from '@testing-library/react'

import {
createRouter,
createRootRoute,
createRoute,
createMemoryHistory,
RouterProvider,
createLink,
Link,
} from '../src'

afterEach(() => {
cleanup()
})

describe('Link', () => {
it('should NOT pass the "disabled" prop to the rendered Link component', async () => {
const rootRoute = createRootRoute()
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => (
<Link to="/" disabled>
Index
</Link>
),
})
const router = createRouter({
routeTree: rootRoute.addChildren([indexRoute]),
history: createMemoryHistory({ initialEntries: ['/'] }),
})

await router.load()

const rendered = render(<RouterProvider router={router} />)
const customElement = rendered.queryByText('Index')

expect(customElement!.hasAttribute('disabled')).toBe(false)
})
})

describe('createLink', () => {
it('should pass the "disabled" prop to the rendered target element', async () => {
const CustomLink = createLink('button')

const rootRoute = createRootRoute()
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => (
<CustomLink to="/" disabled>
Index
</CustomLink>
),
})
const router = createRouter({
routeTree: rootRoute.addChildren([indexRoute]),
history: createMemoryHistory({ initialEntries: ['/'] }),
})

await router.load()

const rendered = render(<RouterProvider router={router} />)
const customElement = rendered.queryByText('Index')

expect(customElement!.hasAttribute('disabled')).toBe(true)
expect(customElement!.getAttribute('disabled')).toBe('')
})

it('should pass the "foo" prop to the rendered target element', async () => {
const CustomLink = createLink('button')

const rootRoute = createRootRoute()
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: '/',
component: () => (
<CustomLink
to="/"
// @ts-expect-error
foo="bar"
>
Index
</CustomLink>
),
})
const router = createRouter({
routeTree: rootRoute.addChildren([indexRoute]),
history: createMemoryHistory({ initialEntries: ['/'] }),
})

await router.load()

const rendered = render(<RouterProvider router={router} />)
const customElement = rendered.queryByText('Index')

expect(customElement!.hasAttribute('foo')).toBe(true)
expect(customElement!.getAttribute('foo')).toBe('bar')
})
})

0 comments on commit fbf1d02

Please sign in to comment.