Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[react-events] Tap responder #16628

Merged
merged 2 commits into from
Sep 5, 2019

Conversation

necolas
Copy link
Contributor

@necolas necolas commented Aug 31, 2019

This is a partial replacement for the 'Press' responder:

  1. useTap is scoped to pointers (no keyboard support). Our current thinking is
    that "responders" should be limited to working with pointers, and that they can
    be combined with 'useKeyboard' in user-space. For example, we might create a
    'usePress' hook in user-space that combines 'useTap' with 'useKeyboard' to react
    to both pointers and keyboard interactions.

  2. useTap cancels the gesture once the pointer moves over an element that is
    not within the responder target's subtree. This differs from usePress (and
    React Native), where the gesture remains active after the pointer exits the
    target's subtree and is restarted once the pointer reenters. One of the
    drawbacks with the usePress behavior is that it requires repeatedly measuring
    DOM elements (which can cause jank) to perform hit region tests. useTap avoids
    doing this and relies on document.elementFromPoint only to support the
    TouchEvent fallbacks.

  3. useTap calls onTapUpdate when the active gesture's state changes,
    onTapEnd when the gesture successfully completes. and onTapCancel when it
    fails. There is no onTap callback. usePress did not explicitly report back
    when the gesture failed, and product developers were confused about the
    difference between onPress and onPressEnd.

  4. useTap explicitly separates the PointerEvent implementation from the
    MouseEvent/TouchEvent fallback.

  5. useTap has better unit test coverage . All pointer types and the fallback
    environment are tested. The shape of the gesture state object is also defined
    and tested.

Demo

@sizebot
Copy link

sizebot commented Aug 31, 2019

ReactDOM: size: 0.0%, gzip: -0.0%

Details of bundled changes.

Comparing: f512537...23cc4f2

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.profiling.min.js 0.0% -0.0% 115.25 KB 115.25 KB 36.34 KB 36.33 KB NODE_PROFILING
react-dom-server.browser.development.js 0.0% -0.0% 140.9 KB 140.9 KB 36.96 KB 36.96 KB UMD_DEV
ReactDOM-dev.js +0.1% 0.0% 933.83 KB 934.34 KB 206.71 KB 206.8 KB FB_WWW_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 19.74 KB 19.74 KB 7.34 KB 7.34 KB UMD_PROD
react-dom-test-utils.development.js 0.0% -0.0% 57.22 KB 57.22 KB 15.78 KB 15.78 KB UMD_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.78 KB 3.78 KB 1.53 KB 1.53 KB UMD_DEV
react-dom-test-utils.production.min.js 0.0% -0.1% 11.18 KB 11.18 KB 4.15 KB 4.15 KB UMD_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.4% 1.2 KB 1.2 KB 703 B 700 B UMD_PROD
react-dom-test-utils.development.js 0.0% -0.0% 55.49 KB 55.49 KB 15.45 KB 15.45 KB NODE_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 3.61 KB 3.61 KB 1.48 KB 1.48 KB NODE_DEV
react-dom-test-utils.production.min.js 0.0% -0.0% 10.95 KB 10.95 KB 4.09 KB 4.09 KB NODE_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.3% 1.04 KB 1.04 KB 634 B 632 B NODE_PROD
react-dom.development.js 0.0% 0.0% 909.72 KB 910.07 KB 206.59 KB 206.65 KB UMD_DEV
react-dom.production.min.js 0.0% -0.0% 111.64 KB 111.64 KB 36.01 KB 36.01 KB UMD_PROD
react-dom.profiling.min.js 0.0% -0.0% 115.05 KB 115.05 KB 37.05 KB 37.05 KB UMD_PROFILING
react-dom.development.js 0.0% 0.0% 904.01 KB 904.37 KB 204.98 KB 205.04 KB NODE_DEV
react-dom-server.node.development.js 0.0% -0.0% 138.05 KB 138.05 KB 36.25 KB 36.24 KB NODE_DEV
react-dom.production.min.js 0.0% -0.0% 111.61 KB 111.61 KB 35.42 KB 35.42 KB NODE_PROD
react-dom-server.node.production.min.js 0.0% -0.0% 20.07 KB 20.07 KB 7.49 KB 7.48 KB NODE_PROD
ReactDOM-prod.js 0.0% 🔺+0.1% 369.71 KB 369.78 KB 67.8 KB 67.85 KB FB_WWW_PROD
ReactDOM-profiling.js 0.0% +0.1% 374.44 KB 374.51 KB 68.85 KB 68.91 KB FB_WWW_PROFILING
react-dom-server.browser.development.js 0.0% -0.0% 137.03 KB 137.03 KB 36.02 KB 36.02 KB NODE_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 19.66 KB 19.66 KB 7.33 KB 7.33 KB NODE_PROD
react-dom-unstable-native-dependencies.development.js 0.0% -0.0% 60.71 KB 60.71 KB 15.85 KB 15.84 KB UMD_DEV
react-dom-unstable-native-dependencies.production.min.js 0.0% -0.1% 10.75 KB 10.75 KB 3.68 KB 3.67 KB UMD_PROD
ReactDOMServer-dev.js 0.0% -0.0% 141.34 KB 141.34 KB 35.6 KB 35.6 KB FB_WWW_DEV
ReactDOMServer-prod.js 0.0% -0.0% 48.13 KB 48.13 KB 11.05 KB 11.05 KB FB_WWW_PROD
react-dom-unstable-native-dependencies.development.js 0.0% -0.0% 60.39 KB 60.39 KB 15.72 KB 15.72 KB NODE_DEV
react-dom-unstable-fizz.node.development.js 0.0% -0.1% 3.87 KB 3.87 KB 1.51 KB 1.51 KB NODE_DEV
react-dom-unstable-native-dependencies.production.min.js 0.0% -0.1% 10.49 KB 10.49 KB 3.58 KB 3.58 KB NODE_PROD
react-dom-unstable-fizz.node.production.min.js 0.0% -0.3% 1.1 KB 1.1 KB 668 B 666 B NODE_PROD

react-events

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-events-focus.development.js 0.0% -0.2% 10.9 KB 10.9 KB 2.35 KB 2.35 KB UMD_DEV
react-events-press.development.js 0.0% -0.1% 21.08 KB 21.08 KB 4.96 KB 4.96 KB UMD_DEV
react-events-focus.production.min.js 0.0% -0.2% 4.08 KB 4.08 KB 1.38 KB 1.38 KB UMD_PROD
react-events-press.production.min.js 0.0% -0.1% 7 KB 7 KB 2.62 KB 2.62 KB UMD_PROD
react-events-context-menu.development.js 0.0% -0.2% 2.67 KB 2.67 KB 1001 B 999 B UMD_DEV
react-events-input.development.js 0.0% -0.2% 4.52 KB 4.52 KB 1.44 KB 1.43 KB UMD_DEV
react-events-swipe.development.js 0.0% -0.2% 5.99 KB 5.99 KB 1.62 KB 1.62 KB UMD_DEV
react-events-context-menu.production.min.js 0.0% -0.4% 1.38 KB 1.38 KB 726 B 723 B UMD_PROD
react-events-input.production.min.js 0.0% -0.3% 1.82 KB 1.82 KB 973 B 970 B UMD_PROD
react-events-swipe.production.min.js 0.0% -0.3% 2.43 KB 2.43 KB 1.1 KB 1.1 KB UMD_PROD
ReactEventsTap-dev.js n/a n/a 0 B 13.97 KB 0 B 3.09 KB FB_WWW_DEV
ReactEventsTap-prod.js n/a n/a 0 B 11.65 KB 0 B 2.58 KB FB_WWW_PROD
react-events-context-menu.development.js 0.0% -0.3% 2.48 KB 2.48 KB 956 B 953 B NODE_DEV
react-events-input.development.js 0.0% -0.2% 4.33 KB 4.33 KB 1.39 KB 1.38 KB NODE_DEV
react-events-swipe.development.js 0.0% -0.2% 5.81 KB 5.81 KB 1.58 KB 1.57 KB NODE_DEV
react-events-context-menu.production.min.js 0.0% -0.5% 1.19 KB 1.19 KB 666 B 663 B NODE_PROD
react-events-input.production.min.js 0.0% -0.2% 1.64 KB 1.64 KB 907 B 905 B NODE_PROD
react-events-swipe.production.min.js 0.0% -0.3% 2.25 KB 2.25 KB 1.04 KB 1.04 KB NODE_PROD
react-events-hover.development.js 0.0% -0.2% 6.98 KB 6.98 KB 1.55 KB 1.54 KB UMD_DEV
react-events-scroll.development.js 0.0% -0.1% 6.29 KB 6.29 KB 1.65 KB 1.65 KB UMD_DEV
react-events-hover.production.min.js 0.0% -0.3% 3.1 KB 3.1 KB 1.13 KB 1.12 KB UMD_PROD
react-events-scroll.production.min.js 0.0% -0.2% 2.61 KB 2.61 KB 1.14 KB 1.14 KB UMD_PROD
react-events-hover.development.js 0.0% -0.1% 6.8 KB 6.8 KB 1.5 KB 1.5 KB NODE_DEV
react-events-scroll.development.js 0.0% -0.1% 6.11 KB 6.11 KB 1.61 KB 1.6 KB NODE_DEV
react-events-hover.production.min.js 0.0% -0.2% 2.92 KB 2.92 KB 1.07 KB 1.06 KB NODE_PROD
react-events-scroll.production.min.js 0.0% -0.3% 2.43 KB 2.43 KB 1.09 KB 1.08 KB NODE_PROD
react-events-focus.development.js 0.0% -0.2% 10.72 KB 10.72 KB 2.31 KB 2.31 KB NODE_DEV
react-events-press.development.js 0.0% -0.1% 20.9 KB 20.9 KB 4.91 KB 4.91 KB NODE_DEV
react-events-focus.production.min.js 0.0% -0.2% 3.91 KB 3.91 KB 1.31 KB 1.31 KB NODE_PROD
react-events-press.production.min.js 0.0% -0.2% 6.83 KB 6.83 KB 2.57 KB 2.56 KB NODE_PROD
react-events-drag.development.js 0.0% -0.2% 5.21 KB 5.21 KB 1.54 KB 1.53 KB UMD_DEV
react-events-keyboard.development.js 0.0% -0.1% 4.3 KB 4.3 KB 1.64 KB 1.63 KB UMD_DEV
react-events-tap.development.js n/a n/a 0 B 14.31 KB 0 B 3.2 KB UMD_DEV
react-events-drag.production.min.js 0.0% -0.2% 2.24 KB 2.24 KB 1.07 KB 1.07 KB UMD_PROD
react-events-keyboard.production.min.js 0.0% -0.1% 1.87 KB 1.87 KB 1.01 KB 1.01 KB UMD_PROD
react-events-tap.production.min.js n/a n/a 0 B 5.2 KB 0 B 2.03 KB UMD_PROD
react-events-drag.development.js 0.0% -0.1% 6.97 KB 6.97 KB 2.2 KB 2.2 KB NODE_DEV
react-events-keyboard.development.js 0.0% -0.1% 4.11 KB 4.11 KB 1.59 KB 1.58 KB NODE_DEV
react-events-tap.development.js n/a n/a 0 B 16.08 KB 0 B 3.86 KB NODE_DEV
react-events-drag.production.min.js 0.0% -0.2% 2.87 KB 2.87 KB 1.38 KB 1.37 KB NODE_PROD
react-events-keyboard.production.min.js 0.0% -0.1% 1.69 KB 1.69 KB 961 B 960 B NODE_PROD
react-events-tap.production.min.js n/a n/a 0 B 5.9 KB 0 B 2.38 KB NODE_PROD

Generated by 🚫 dangerJS

@necolas necolas force-pushed the react-events/tap-responder branch from 1655201 to 6a7c145 Compare August 31, 2019 00:58
Copy link
Contributor Author

@necolas necolas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll consolidate the common logic within the different responder implementations now that all the tests pass.

@necolas necolas force-pushed the react-events/tap-responder branch from 6a7c145 to 9df4e0b Compare August 31, 2019 01:56
@TrySound
Copy link
Contributor

TrySound commented Sep 1, 2019

Using useKeyboard in user space may lead to inconsistent UX. I thought the point of builtin usePress was to avoid opinions here. There was a case with scrolling down on pressing space. Is it considered in new implementation?

Copy link
Contributor

@trueadm trueadm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very thorough, I love it. Let's get this in once we've got keyboard updated to reflect the previous Press :)

@trueadm
Copy link
Contributor

trueadm commented Sep 3, 2019

@TrySound We'll still provide usePress hook that uses a combination of these responders under-the-hood and we'll recommend people continue to use that hook that the case where it's the desired behavior.

@necolas necolas force-pushed the react-events/tap-responder branch from 9df4e0b to e59a72c Compare September 3, 2019 21:03
packages/react-events/src/dom/Tap.js Outdated Show resolved Hide resolved
packages/react-events/src/dom/Tap.js Outdated Show resolved Hide resolved
packages/react-events/src/dom/Tap.js Outdated Show resolved Hide resolved
packages/react-events/src/dom/Tap.js Outdated Show resolved Hide resolved
This is a partial replacement for the 'Press' responder:

1. `useTap` is scoped to pointers (no keyboard support). Our current thinking is
that "responders" should be limited to working with pointers, and that they can
be combined with 'useKeyboard' in user-space. For example, we might create a
'usePress' hook in user-space that combines 'useTap' with 'useKeyboard' to react
to both pointers and keyboard interactions.

2. `useTap` cancels the gesture once the pointer moves over an element that is
not within the responder target's subtree. This differs from `usePress` (and
React Native), where the gesture remains active after the pointer exits the
target's subtree and is restarted once the pointer reenters. One of the
drawbacks with the `usePress` behavior is that it requires repeatedly measuring
DOM elements (which can cause jank) to perform hit region tests. `useTap` avoids
doing this and relies on `document.elementFromPoint` only to support the
TouchEvent fallbacks.

3. `useTap` calls `onTapUpdate` when the active gesture's state changes,
`onTapEnd` when the gesture successfully completes. and `onTapCancel` when it
fails. There is no `onTap` callback. `usePress` did not explicitly report back
when the gesture failed, and product developers were confused about the
difference between `onPress` and `onPressEnd`.

4. `useTap` explicitly separates the PointerEvent implementation from the
MouseEvent/TouchEvent fallback.

5. `useTap` has better unit test coverage . All pointer types and the fallback
environment are tested. The shape of the gesture state object is also defined
and tested.
@necolas necolas force-pushed the react-events/tap-responder branch 4 times, most recently from f005593 to c8aa125 Compare September 4, 2019 22:48
@sizebot
Copy link

sizebot commented Sep 4, 2019

Details of bundled changes.

Comparing: c66edb9...cb40f04

react-events

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-events-focus.development.js 0.0% +0.1% 10.91 KB 10.91 KB 2.35 KB 2.36 KB UMD_DEV
react-events-press.development.js -0.2% -0.2% 21.24 KB 21.21 KB 4.97 KB 4.96 KB UMD_DEV
react-events-focus.production.min.js 0.0% 🔺+0.1% 4.09 KB 4.09 KB 1.39 KB 1.39 KB UMD_PROD
react-events-press.production.min.js 🔺+0.1% 🔺+0.1% 7.05 KB 7.06 KB 2.63 KB 2.63 KB UMD_PROD
react-events-context-menu.development.js 0.0% +0.1% 2.67 KB 2.67 KB 999 B 1000 B UMD_DEV
react-events-input.development.js 0.0% +0.1% 4.51 KB 4.51 KB 1.44 KB 1.44 KB UMD_DEV
react-events-context-menu.production.min.js 0.0% 🔺+0.1% 1.38 KB 1.38 KB 724 B 725 B UMD_PROD
react-events-input.production.min.js 0.0% 🔺+0.1% 1.83 KB 1.83 KB 977 B 978 B UMD_PROD
react-events-swipe.production.min.js 0.0% 🔺+0.1% 2.43 KB 2.43 KB 1.1 KB 1.1 KB UMD_PROD
ReactEventsTap-dev.js n/a n/a 0 B 15.06 KB 0 B 3.31 KB FB_WWW_DEV
ReactEventsTap-prod.js n/a n/a 0 B 12.2 KB 0 B 2.73 KB FB_WWW_PROD
react-events-context-menu.development.js 0.0% +0.1% 2.48 KB 2.48 KB 953 B 954 B NODE_DEV
react-events-input.development.js 0.0% +0.1% 4.33 KB 4.33 KB 1.39 KB 1.39 KB NODE_DEV
react-events-swipe.development.js 0.0% +0.1% 5.81 KB 5.81 KB 1.58 KB 1.58 KB NODE_DEV
react-events-context-menu.production.min.js 0.0% 🔺+0.3% 1.19 KB 1.19 KB 663 B 665 B NODE_PROD
react-events-swipe.production.min.js 0.0% 🔺+0.1% 2.25 KB 2.25 KB 1.04 KB 1.04 KB NODE_PROD
react-events-hover.development.js 0.0% +0.1% 6.99 KB 6.99 KB 1.55 KB 1.55 KB UMD_DEV
react-events-scroll.development.js 0.0% +0.1% 6.29 KB 6.29 KB 1.65 KB 1.65 KB UMD_DEV
react-events-hover.production.min.js 0.0% 🔺+0.1% 3.11 KB 3.11 KB 1.13 KB 1.13 KB UMD_PROD
react-events-scroll.production.min.js 0.0% 🔺+0.2% 2.61 KB 2.61 KB 1.14 KB 1.14 KB UMD_PROD
react-events-hover.development.js 0.0% +0.1% 6.81 KB 6.81 KB 1.5 KB 1.5 KB NODE_DEV
react-events-scroll.development.js 0.0% +0.1% 6.11 KB 6.11 KB 1.6 KB 1.6 KB NODE_DEV
react-events-scroll.production.min.js 0.0% 🔺+0.1% 2.43 KB 2.43 KB 1.08 KB 1.09 KB NODE_PROD
react-events-focus.development.js 0.0% +0.1% 10.73 KB 10.73 KB 2.31 KB 2.31 KB NODE_DEV
react-events-press.development.js -0.2% -0.2% 21.06 KB 21.02 KB 4.92 KB 4.91 KB NODE_DEV
react-events-focus.production.min.js 0.0% 🔺+0.1% 3.92 KB 3.92 KB 1.32 KB 1.32 KB NODE_PROD
react-events-press.production.min.js 🔺+0.1% 🔺+0.1% 6.87 KB 6.88 KB 2.58 KB 2.58 KB NODE_PROD
react-events-drag.development.js 0.0% +0.1% 5.21 KB 5.21 KB 1.54 KB 1.54 KB UMD_DEV
react-events-tap.development.js n/a n/a 0 B 15.49 KB 0 B 3.42 KB UMD_DEV
react-events-drag.production.min.js 0.0% 🔺+0.1% 2.24 KB 2.24 KB 1.07 KB 1.07 KB UMD_PROD
react-events-keyboard.production.min.js 0.0% -0.1% 2.25 KB 2.25 KB 1.2 KB 1.19 KB UMD_PROD
ReactEventsPress-dev.js +0.1% 0.0% 21.84 KB 21.87 KB 5.11 KB 5.11 KB FB_WWW_DEV
react-events-tap.production.min.js n/a n/a 0 B 5.54 KB 0 B 2.17 KB UMD_PROD
ReactEventsPress-prod.js 🔺+1.0% 🔺+0.5% 16.18 KB 16.34 KB 3.56 KB 3.57 KB FB_WWW_PROD
react-events-tap.development.js n/a n/a 0 B 17.26 KB 0 B 4.06 KB NODE_DEV
react-events-tap.production.min.js n/a n/a 0 B 6.24 KB 0 B 2.5 KB NODE_PROD

Generated by 🚫 dangerJS against cb40f04

if (type === 'pointermove' && activePointerId !== pointerId) {
if (
type === 'pointermove' &&
activePointerId !== nativeEvent.pointerId
Copy link
Contributor

@trueadm trueadm Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not extract pointerId above? You use it just below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value is only used (and not null) within the the PointerEvent branches.

Copy link
Contributor

@trueadm trueadm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments.

Reduces the minified size most. Smaller percentage improvement for gzip.
@necolas necolas force-pushed the react-events/tap-responder branch from c8aa125 to cb40f04 Compare September 4, 2019 23:27
Copy link
Contributor

@trueadm trueadm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you addressed my changes. So I'm cool with this – please make sure we cover Firefox for Android though. I know it's not a large % of users, but it's relatively easy to guard against.

@necolas necolas merged commit 9ce8711 into facebook:master Sep 5, 2019
@necolas necolas deleted the react-events/tap-responder branch December 20, 2019 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants