Skip to content

Commit

Permalink
Fix adobe#918 Adding preventFocusOnPress to usePress (adobe#1073)
Browse files Browse the repository at this point in the history
  • Loading branch information
LFDanLu authored Sep 29, 2020
1 parent 43514ea commit 9e1d8d6
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 6 deletions.
13 changes: 8 additions & 5 deletions packages/@react-aria/interactions/src/usePress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export interface PressProps extends PressEvents {
/** Whether the target is in a controlled press state (e.g. an overlay it triggers is open). */
isPressed?: boolean,
/** Whether the press events should be disabled. */
isDisabled?: boolean
isDisabled?: boolean,
/** Whether the target should not receive focus on press. */
preventFocusOnPress?: boolean
}

export interface PressHookProps extends PressProps {
Expand Down Expand Up @@ -93,6 +95,7 @@ export function usePress(props: PressHookProps): PressResult {
onPressUp,
isDisabled,
isPressed: isPressedProp,
preventFocusOnPress,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
ref: _, // Removing `ref` from `domProps` because TypeScript is dumb
...domProps
Expand Down Expand Up @@ -233,7 +236,7 @@ export function usePress(props: PressHookProps): PressResult {
// trigger as if it were a keyboard click.
if (!state.ignoreClickAfterPress && !state.ignoreEmulatedMouseEvents && isVirtualClick(e.nativeEvent)) {
// Ensure the element receives focus (VoiceOver on iOS does not do this)
if (!isDisabled) {
if (!isDisabled && !preventFocusOnPress) {
focusWithoutScrolling(e.currentTarget);
}

Expand Down Expand Up @@ -307,7 +310,7 @@ export function usePress(props: PressHookProps): PressResult {
state.activePointerId = e.pointerId;
state.target = e.currentTarget;

if (!isDisabled) {
if (!isDisabled && !preventFocusOnPress) {
focusWithoutScrolling(e.currentTarget);
}

Expand Down Expand Up @@ -410,7 +413,7 @@ export function usePress(props: PressHookProps): PressResult {
state.isOverTarget = true;
state.target = e.currentTarget;

if (!isDisabled) {
if (!isDisabled && !preventFocusOnPress) {
focusWithoutScrolling(e.currentTarget);
}

Expand Down Expand Up @@ -479,7 +482,7 @@ export function usePress(props: PressHookProps): PressResult {

// Due to browser inconsistencies, especially on mobile browsers, we prevent default
// on the emulated mouse event and handle focusing the pressable element ourselves.
if (!isDisabled) {
if (!isDisabled && !preventFocusOnPress) {
focusWithoutScrolling(e.currentTarget);
}

Expand Down
96 changes: 95 additions & 1 deletion packages/@react-aria/interactions/test/usePress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {usePress} from '../';
function Example(props) {
let {elementType: ElementType = 'div', ...otherProps} = props;
let {pressProps} = usePress(otherProps);
return <ElementType {...pressProps}>test</ElementType>;
return <ElementType {...pressProps} tabIndex="0">test</ElementType>;
}

function pointerEvent(type, opts) {
Expand Down Expand Up @@ -347,6 +347,28 @@ describe('usePress', function () {
fireEvent(el, pointerEvent('pointerup', {pointerId: 1, pointerType: 'mouse', button: 1, clientX: 0, clientY: 0}));
expect(events).toEqual([]);
});

it('should not focus the target on click if preventFocusOnPress is true', function () {
let res = render(
<Example preventFocusOnPress />
);

let el = res.getByText('test');
fireEvent(el, pointerEvent('pointerdown', {pointerId: 1, pointerType: 'mouse'}));
fireEvent(el, pointerEvent('pointerup', {pointerId: 1, pointerType: 'mouse', clientX: 0, clientY: 0}));
expect(document.activeElement).not.toBe(el);
});

it('should focus the target on click by default', function () {
let res = render(
<Example />
);

let el = res.getByText('test');
fireEvent(el, pointerEvent('pointerdown', {pointerId: 1, pointerType: 'mouse'}));
fireEvent(el, pointerEvent('pointerup', {pointerId: 1, pointerType: 'mouse', clientX: 0, clientY: 0}));
expect(document.activeElement).toBe(el);
});
});

describe('mouse events', function () {
Expand Down Expand Up @@ -611,6 +633,32 @@ describe('usePress', function () {

expect(events).toEqual([]);
});

it('should not focus the element on click if preventFocusOnPress is true', function () {
let res = render(
<Example preventFocusOnPress />
);

let el = res.getByText('test');
fireEvent.mouseDown(el);
fireEvent.mouseUp(el);
fireEvent.click(el);

expect(document.activeElement).not.toBe(el);
});

it('should focus the element on click by default', function () {
let res = render(
<Example />
);

let el = res.getByText('test');
fireEvent.mouseDown(el);
fireEvent.mouseUp(el);
fireEvent.click(el);

expect(document.activeElement).toBe(el);
});
});

describe('touch events', function () {
Expand Down Expand Up @@ -1039,6 +1087,30 @@ describe('usePress', function () {
}
]);
});

it('should not focus the target if preventFocusOnPress is true', function () {
let res = render(
<Example preventFocusOnPress />
);

let el = res.getByText('test');
fireEvent.touchStart(el, {targetTouches: [{identifier: 1}]});
fireEvent.touchEnd(el, {changedTouches: [{identifier: 1, clientX: 0, clientY: 0}]});

expect(document.activeElement).not.toBe(el);
});

it('should focus the target on touch by default', function () {
let res = render(
<Example />
);

let el = res.getByText('test');
fireEvent.touchStart(el, {targetTouches: [{identifier: 1}]});
fireEvent.touchEnd(el, {changedTouches: [{identifier: 1, clientX: 0, clientY: 0}]});

expect(document.activeElement).toBe(el);
});
});

describe('keyboard events', function () {
Expand Down Expand Up @@ -1557,4 +1629,26 @@ describe('usePress', function () {
]);
});
});

it('should not focus the target if preventFocusOnPress is true', function () {
let {getByText} = render(
<Example preventFocusOnPress />
);

let el = getByText('test');
fireEvent.click(el);

expect(document.activeElement).not.toBe(el);
});

it('should focus the target on virtual click by default', function () {
let {getByText} = render(
<Example />
);

let el = getByText('test');
fireEvent.click(el);

expect(document.activeElement).toBe(el);
});
});

0 comments on commit 9e1d8d6

Please sign in to comment.