Skip to content

Commit

Permalink
Trigger non-touch events on box-none targets (#906)
Browse files Browse the repository at this point in the history
* Trigger non-touch events on box-none targets

Currently, this library disables _all_ events for a target with
`pointerEvents="box-none"`. This behavior is counter to how React Native
itself functions. This change continues to disable touch events, e.g.
`press`, for targets set to "box-none", but allows triggering non-touch
events, e.g. `layout`, `touchStart`.

* Event triggers target box-none View instead of child

This approach more closely aligns with the original failing test case.

* Rename events in test description

Attempt to better communicate the test is focused on ensuring that touch
events continue to trigger (e.g. `touchStart`), but the final event from
a touch tap does not trigger.
  • Loading branch information
dcalhoun authored Jul 19, 2022
1 parent 8ce39f5 commit d2269f6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 3 deletions.
34 changes: 34 additions & 0 deletions src/__tests__/fireEvent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,40 @@ test('should not fire on box-only pointerEvents View with nested elements', () =
expect(handlePress).not.toHaveBeenCalled();
});

test('should fire non-pointer events on box-none pointerEvents View', () => {
const handleTouchStart = jest.fn();

const screen = render(
<View
pointerEvents="box-none"
onTouchStart={handleTouchStart}
testID="touch-start-view"
>
<Pressable onPress={() => {}}>
<Text>Trigger</Text>
</Pressable>
</View>
);

fireEvent(screen.getByTestId('touch-start-view'), 'touchStart');
expect(handleTouchStart).toHaveBeenCalled();
});

test('should fire non-touch events on box-none pointerEvents View', () => {
const handleLayout = jest.fn();

const screen = render(
<View pointerEvents="box-none" onLayout={handleLayout} testID="layout-view">
<Pressable onPress={() => {}}>
<Text>Trigger</Text>
</Pressable>
</View>
);

fireEvent(screen.getByTestId('layout-view'), 'layout');
expect(handleLayout).toHaveBeenCalled();
});

test('should pass event up on disabled TouchableOpacity', () => {
const handleInnerPress = jest.fn();
const handleOuterPress = jest.fn();
Expand Down
12 changes: 9 additions & 3 deletions src/fireEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ const isPointerEventEnabled = (
return isPointerEventEnabled(element.parent, true);
};

const isTouchEvent = (eventName?: string) => {
return eventName === 'press';
};

const isEventEnabled = (
element?: ReactTestInstance,
touchResponder?: ReactTestInstance
touchResponder?: ReactTestInstance,
eventName?: string
) => {
if (isTextInput(element)) return element?.props.editable !== false;
if (!isPointerEventEnabled(element)) return false;
if (!isPointerEventEnabled(element) && isTouchEvent(eventName)) return false;

const touchStart = touchResponder?.props.onStartShouldSetResponder?.();
const touchMove = touchResponder?.props.onMoveShouldSetResponder?.();
Expand All @@ -61,7 +66,8 @@ const findEventHandler = (
: nearestTouchResponder;

const handler = getEventHandler(element, eventName);
if (handler && isEventEnabled(element, touchResponder)) return handler;
if (handler && isEventEnabled(element, touchResponder, eventName))
return handler;

if (element.parent === null || element.parent.parent === null) {
return null;
Expand Down

0 comments on commit d2269f6

Please sign in to comment.