mirror of
https://github.com/facebook/react.git
synced 2026-02-25 05:03:03 +00:00
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.
79 lines
2.0 KiB
JavaScript
79 lines
2.0 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {
|
|
ReactFundamentalComponentInstance,
|
|
ReactEventResponder,
|
|
ReactEventResponderInstance,
|
|
EventPriority,
|
|
} from 'shared/ReactTypes';
|
|
|
|
type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | Touch;
|
|
|
|
export type PointerType =
|
|
| ''
|
|
| 'mouse'
|
|
| 'keyboard'
|
|
| 'pen'
|
|
| 'touch'
|
|
| 'trackpad';
|
|
|
|
export type ReactDOMResponderEvent = {
|
|
nativeEvent: AnyNativeEvent,
|
|
passive: boolean,
|
|
passiveSupported: boolean,
|
|
pointerType: PointerType,
|
|
target: Element | Document,
|
|
type: string,
|
|
};
|
|
|
|
export type ReactDOMEventResponder = ReactEventResponder<
|
|
ReactDOMResponderEvent,
|
|
ReactDOMResponderContext,
|
|
>;
|
|
|
|
export type ReactDOMEventResponderInstance = ReactEventResponderInstance<
|
|
ReactDOMResponderEvent,
|
|
ReactDOMResponderContext,
|
|
>;
|
|
|
|
export type ReactDOMFundamentalComponentInstance = ReactFundamentalComponentInstance<
|
|
any,
|
|
any,
|
|
>;
|
|
|
|
export type ReactDOMResponderContext = {
|
|
dispatchEvent: (
|
|
eventValue: any,
|
|
listener: (any) => void,
|
|
eventPriority: EventPriority,
|
|
) => void,
|
|
isTargetWithinNode: (
|
|
childTarget: null | Element | Document,
|
|
parentTarget: Element | Document,
|
|
) => boolean,
|
|
isTargetWithinResponder: (null | Element | Document) => boolean,
|
|
isTargetWithinResponderScope: (null | Element | Document) => boolean,
|
|
addRootEventTypes: (rootEventTypes: Array<string>) => void,
|
|
removeRootEventTypes: (rootEventTypes: Array<string>) => void,
|
|
setTimeout: (func: () => void, timeout: number) => number,
|
|
clearTimeout: (timerId: number) => void,
|
|
getActiveDocument(): Document,
|
|
objectAssign: Function,
|
|
getTimeStamp: () => number,
|
|
isTargetWithinHostComponent: (
|
|
target: Element | Document,
|
|
elementType: string,
|
|
) => boolean,
|
|
continuePropagation(): void,
|
|
// Used for controller components
|
|
enqueueStateRestore(Element | Document): void,
|
|
getResponderNode(): Element | null,
|
|
};
|