Skip to content

Commit

Permalink
fix(react-link): support Enter and Space keys interaction, if rendere…
Browse files Browse the repository at this point in the history
…d as span (#33587)
  • Loading branch information
mainframev authored Jan 15, 2025
1 parent 087380a commit 928fdce
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: support Enter and Space interaction, if rendered as span",
"packageName": "@fluentui/react-link",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { linkBehaviorDefinition, validateBehavior, ComponentTestFacade } from '@fluentui/a11y-testing';
import { isConformant } from '../../testing/isConformant';
import { Link } from './Link';
import { LinkProps } from './Link.types';
import { Enter } from '@fluentui/keyboard-keys';

describe('Link', () => {
isConformant<LinkProps>({
Expand Down Expand Up @@ -140,5 +142,62 @@ describe('Link', () => {
expect(result.queryAllByRole('link')).toHaveLength(0);
expect(result.queryAllByRole('presentation')).toHaveLength(1);
});

describe('when rendered as span', () => {
it('should call onClick by pressing Enter', () => {
const onClick = jest.fn();

render(
<Link as="span" onClick={onClick}>
This is a buttonlink
</Link>,
);

userEvent.tab();
userEvent.keyboard('{Enter}');

expect(onClick).toHaveBeenCalledTimes(1);
});

it('should trigger onClick once via onKeyDown', () => {
const onClick = jest.fn();

render(
<Link
as="span"
onClick={onClick}
onKeyDown={ev => {
if (ev.key === Enter) {
ev.currentTarget.click();
}
}}
>
This is a buttonlink
</Link>,
);

userEvent.tab();
userEvent.keyboard('{Enter}');

expect(onClick).toHaveBeenCalledTimes(1);
});

it('should not trigger onClick', () => {
const onClick = jest.fn();
const onKeyDown = jest.fn();

render(
<Link as="span" onClick={onClick} onKeyDown={onKeyDown}>
This is a buttonlink
</Link>,
);

userEvent.tab();
userEvent.keyboard('{Enter}');

expect(onClick).toHaveBeenCalledTimes(0);
expect(onKeyDown).toHaveBeenCalledTimes(1);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,18 @@ export const useLinkState_unstable = (state: LinkState): LinkState => {

// Disallow keydown event when component is disabled and eat events when disabledFocusable is set to true.
state.root.onKeyDown = (ev: React.KeyboardEvent<HTMLAnchorElement & HTMLButtonElement>) => {
if ((disabled || disabledFocusable) && (ev.key === Enter || ev.key === Space)) {
const keyPressed = ev.key === Enter || ev.key === Space;

if ((disabled || disabledFocusable) && keyPressed) {
ev.preventDefault();
ev.stopPropagation();
} else {
onKeyDown?.(ev);
// if there is already onKeyDown provided - respect it
if (state.root.as === 'span' && !!state.root.onClick && !onKeyDown && keyPressed) {
ev.preventDefault();
ev.currentTarget.click();
}
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const useDivWithWidthClassName = makeResetStyles({
export const AsSpan = () => (
<div className={useDivWithWidthClassName()}>
The following link renders as a span.{' '}
<Link as="span" inline>
<Link as="span" inline onClick={() => alert('Link rendered as span')}>
Links that render as a span wrap correctly between lines when their content is very long
</Link>
. This is because they behave as regular inline elements.
Expand Down

0 comments on commit 928fdce

Please sign in to comment.