Skip to content

Commit

Permalink
[add] Pressable support for hover state
Browse files Browse the repository at this point in the history
This patch ports the 'useHover' hook to React Native for Web, providing hover
state that is scoped to a pressable and does not bubble to ancestor pressables.
This behavior aligns with the behavior of the focus and press states.

Fix #1708
  • Loading branch information
necolas committed Sep 11, 2020
1 parent b6603ad commit 1afd9de
Show file tree
Hide file tree
Showing 20 changed files with 2,304 additions and 182 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"env": {
"browser": true,
"es6": true,
"jest": true,
"node": true
},
"globals": {
Expand Down
49 changes: 35 additions & 14 deletions packages/docs/src/components/Pressable/examples/FeedbackEvents.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,48 @@ export default function FeedbackEvents() {
onPress={handlePress('press')}
onPressIn={handlePress('pressIn')}
onPressOut={handlePress('pressOut')}
style={({ pressed, focused }) => ({
padding: 10,
margin: 10,
borderWidth: 1,
borderColor: focused ? 'blue' : null,
backgroundColor: pressed ? 'lightblue' : 'white'
})}
style={({ hovered, pressed, focused }) => {
let backgroundColor = 'white';
if (hovered) {
backgroundColor = 'lightgray';
}
if (pressed) {
backgroundColor = 'lightblue';
}
return {
padding: 10,
margin: 10,
borderWidth: 1,
borderColor: focused ? 'red' : null,
backgroundColor,
outlineWidth: 0
};
}}
>
<Pressable
accessibilityRole="none"
onLongPress={handlePress('longPress - inner')}
onPress={handlePress('press - inner')}
onPressIn={handlePress('pressIn - inner')}
onPressOut={handlePress('pressOut - inner')}
style={({ pressed, focused }) => ({
padding: 10,
margin: 10,
borderWidth: 1,
borderColor: focused ? 'blue' : null,
backgroundColor: pressed ? 'lightblue' : 'white'
})}
style={({ hovered, pressed, focused }) => {
console.log(focused);
let backgroundColor = 'white';
if (hovered) {
backgroundColor = 'lightgray';
}
if (pressed) {
backgroundColor = 'lightblue';
}
return {
padding: 10,
margin: 10,
borderWidth: 1,
borderColor: focused ? 'red' : null,
backgroundColor,
outlineWidth: 0
};
}}
>
<Text>Nested pressables</Text>
</Pressable>
Expand Down
57 changes: 26 additions & 31 deletions packages/dom-event-testing-library/README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
# `dom-event-testing-library`

A library for unit testing high-level interactions via simple pointer events, e.g.,
`pointerdown`, that produce realistic and complete DOM event sequences.
A library for unit testing high-level interactions via simple pointer events, e.g., `pointerdown`, that produce realistic and complete DOM event sequences.

There are number of challenges involved in unit testing modules that work with
DOM events.
There are number of challenges involved in unit testing modules that work with DOM events.

1. Testing environments with and without support for the `PointerEvent` API.
2. Testing various user interaction modes including mouse, touch, and pen use.
3. Testing against the event sequences browsers actually produce (e.g., emulated
touch and mouse events.)
4. Testing against the event properties DOM events include (i.e., more complete
mock data)
4. Testing against "virtual" events produced by tools like screen-readers.
3. Testing against the event sequences browsers actually produce (e.g., emulated touch and mouse events.)
4. Testing against the event properties DOM events include (i.e., more complete mock data)
5. Testing against "virtual" events produced by tools like screen-readers.

Writing unit tests to cover all these scenarios is tedious and error prone. This
event testing library is designed to avoid these issues by allowing developers to
more easily dispatch events in unit tests, and to more reliably test interactions
while using an API based on `PointerEvent`.
Writing unit tests to cover all these scenarios is tedious and error prone. This event testing library is designed to avoid these issues by allowing developers to more easily dispatch events in unit tests, and to more reliably test interactions while using an API based on `PointerEvent`.

## Example

Expand Down Expand Up @@ -45,34 +38,37 @@ describeWithPointerEvent('useTap', hasPointerEvent => {
testWithPointerType('pointer down', pointerType => {
const ref = createRef(null);
const onTapStart = jest.fn();
render(() => {
useTap(ref, { onTapStart });

// component to test
function Component() {
useTapEvents(ref, { onTapStart });
return <div ref={ref} />
}

// render component
act(() => {
render(<Component />);
});

// create an event target
const target = createEventTarget(ref.current);

// dispatch high-level pointer event
target.pointerdown({ pointerType });
act(() => {
target.pointerdown({ pointerType });
});

// assertion
expect(onTapStart).toBeCalled();
});
});
```

This tests the interaction in multiple scenarios. In each case, a realistic DOM
event sequence–with complete mock events–is produced. When running in a mock
environment without the `PointerEvent` API, the test runs for both `mouse` and
`touch` pointer types. When `touch` is the pointer type it produces emulated mouse
events. When running in a mock environment with the `PointerEvent` API, the test
runs for `mouse`, `touch`, and `pen` pointer types.
The example above tests the interaction in multiple scenarios. In each case, a realistic DOM event sequence–with complete mock events–is produced. When running in a mock environment without the `PointerEvent` API, the test runs for both `mouse` and `touch` pointer types. When `touch` is the pointer type it produces emulated mouse events. When running in a mock environment with the `PointerEvent` API, the test runs for `mouse`, `touch`, and `pen` pointer types.

It's important to cover all these scenarios because it's very easy to introduce
bugs – e.g., double calling of callbacks – if not accounting for emulated mouse
events, differences in target capturing between `touch` and `mouse` pointers, and
the different semantics of `button` across event APIs.
It's important to cover all these scenarios because it's very easy to introduce bugs – e.g., double calling of callbacks – if not accounting for emulated mouse events, differences in target capturing between `touch` and `mouse` pointers, and the different semantics of `button` across event APIs.

Default values are provided for the expected native events properties. They can
also be customized as needed in a test.
Default values are provided for the expected native events properties. They can also be customized as needed in a test.

```js
target.pointerdown({
Expand All @@ -87,8 +83,7 @@ target.pointerdown({
});
```

Tests that dispatch multiple pointer events will dispatch multi-touch native events
on the target.
Tests that dispatch multiple pointer events will dispatch multi-touch native events on the target.

```js
// first pointer is active
Expand All @@ -106,7 +101,7 @@ To create a new event target pass the DOM node to `createEventTarget(node)`. Thi
* `blur`
* `click`
* `contextmenu`
* `focus`
* `focus` (includes the complete sequence of focus-related events)
* `keydown`
* `keyup`
* `pointercancel`
Expand Down
2 changes: 1 addition & 1 deletion packages/dom-event-testing-library/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "dom-event-testing-library",
"version": "0.13.12",
"version": "0.0.0",
"main": "index.js",
"description": "Browser event sequences for unit tests",
"author": "Nicolas Gallagher",
Expand Down
16 changes: 9 additions & 7 deletions packages/dom-event-testing-library/src/__tests__/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,24 @@ describe('createEventTarget', () => {
"node",
"blur",
"click",
"contextmenu",
"error",
"focus",
"keydown",
"keyup",
"scroll",
"select",
"selectionchange",
"virtualclick",
"contextmenu",
"load",
"pointercancel",
"pointerdown",
"pointerhover",
"pointermove",
"pointerover",
"pointerout",
"pointerup",
"scroll",
"select",
"selectionchange",
"tap",
"virtualclick",
"setBoundingClientRect",
]
`);
Expand All @@ -82,7 +84,7 @@ describe('createEventTarget', () => {
test('default', () => {
const target = createEventTarget(node);
node.addEventListener('blur', e => {
expect(e.relatedTarget).toBeUndefined();
expect(e.relatedTarget).toBeNull();
});
target.blur();
});
Expand Down Expand Up @@ -168,7 +170,7 @@ describe('createEventTarget', () => {
test('default', () => {
const target = createEventTarget(node);
node.addEventListener('focus', e => {
expect(e.relatedTarget).toBeUndefined();
expect(e.relatedTarget).toBeNull();
});
target.focus();
});
Expand Down
Loading

0 comments on commit 1afd9de

Please sign in to comment.