Reorganize usePressEvents and PressResponder

This commit is contained in:
Nicolas Gallagher
2020-04-20 11:40:05 -07:00
parent cf7d5e9b07
commit 37ff6b4888
7 changed files with 50 additions and 23 deletions
+2 -2
View File
@@ -10,13 +10,13 @@
'use strict';
import type { PressResponderConfig } from '../../modules/PressResponder';
import type { PressResponderConfig } from '../../hooks/usePressEvents/PressResponder';
import type { ViewProps } from '../View';
import * as React from 'react';
import { forwardRef, memo, useMemo, useState, useRef } from 'react';
import setAndForwardRef from '../../modules/setAndForwardRef';
import usePressEvents from '../../modules/PressResponder/usePressEvents';
import usePressEvents from '../../hooks/usePressEvents';
import View from '../View';
export type StateCallbackType = $ReadOnly<{|
@@ -16,7 +16,7 @@ import type { ViewProps } from '../View';
import * as React from 'react';
import { useCallback, useMemo, useState, useRef } from 'react';
import usePressEvents from '../../modules/PressResponder/usePressEvents';
import usePressEvents from '../../hooks/usePressEvents';
import setAndForwardRef from '../../modules/setAndForwardRef';
import StyleSheet from '../StyleSheet';
import View from '../View';
@@ -15,7 +15,7 @@ import type { ViewProps } from '../View';
import * as React from 'react';
import { useCallback, useMemo, useState, useRef } from 'react';
import usePressEvents from '../../modules/PressResponder/usePressEvents';
import usePressEvents from '../../hooks/usePressEvents';
import setAndForwardRef from '../../modules/setAndForwardRef';
import StyleSheet from '../StyleSheet';
import View from '../View';
@@ -10,14 +10,14 @@
'use strict';
import type { PressResponderConfig } from '../../modules/PressResponder';
import type { PressResponderConfig } from '../../hooks/usePressEvents/PressResponder';
import type { ViewProps } from '../View';
import * as React from 'react';
import { useMemo, useRef } from 'react';
import pick from '../../modules/pick';
import setAndForwardRef from '../../modules/setAndForwardRef';
import usePressEvents from '../../modules/PressResponder/usePressEvents';
import usePressEvents from '../../hooks/usePressEvents';
export type Props = $ReadOnly<{|
accessibilityLabel?: $PropertyType<ViewProps, 'accessibilityLabel'>,
@@ -11,6 +11,8 @@
'use strict';
import invariant from 'fbjs/lib/invariant';
import isLink from '../../modules/isLink';
import isSelectionValid from '../../modules/isSelectionValid';
type ClickEvent = any;
type KeyboardEvent = any;
@@ -129,6 +131,11 @@ const isPressStartSignal = signal =>
const isTerminalSignal = signal => signal === RESPONDER_TERMINATED || signal === RESPONDER_RELEASE;
const isKeyPress = event => {
const target = event.currentTarget;
return (!isLink(target) && event.key === ' ') || event.key === 'Enter';
};
const DEFAULT_LONG_PRESS_DELAY_MS = 450; // 500 - 50
const DEFAULT_PRESS_DELAY_MS = 50;
@@ -299,21 +306,19 @@ export default class PressResponder {
},
onKeyDown: event => {
if (this._touchState === NOT_RESPONDER) {
if (event.key === ' ' || event.key === 'Enter') {
if (isKeyPress(event)) {
if (this._touchState === NOT_RESPONDER) {
start(event, false);
}
}
if (this._responderID) {
event.stopPropagation();
}
},
onKeyUp: event => {
if (event.key === ' ' || event.key === 'Enter') {
if (isKeyPress(event)) {
end(event);
event.stopPropagation();
}
event.stopPropagation();
},
onResponderGrant: event => start(event),
@@ -356,7 +361,7 @@ export default class PressResponder {
return cancelable;
},
// NOTE: this diverges from react-native@0.62 in 2 significant ways
// NOTE: this diverges from react-native in 3 significant ways:
// * The `onPress` callback is not connected to the responder system (the native
// `click` event must be used but is dispatched in many scenarios where no pointers
// are on the screen.) Therefore, it's possible for `onPress` to be called without
@@ -367,14 +372,15 @@ export default class PressResponder {
onClick: (event: any): void => {
const { disabled, onPress } = this._config;
if (!disabled) {
if (event.nativeEvent.__responderStoppedPropagation !== true) {
if (this._longPressDispatched) {
event.preventDefault();
} else if (event.ctrlKey === false && event.altKey === false && onPress != null) {
onPress(event);
}
event.nativeEvent.__responderStoppedPropagation = true;
// If long press dispatched, cancel default click behavior.
// If text is selected it means the user selected text during the gesture,
// cancel default click behavior.
if (this._longPressDispatched || isSelectionValid()) {
event.preventDefault();
} else if (onPress != null && event.ctrlKey === false && event.altKey === false) {
onPress(event);
}
event.stopPropagation();
}
},
@@ -433,7 +439,9 @@ export default class PressResponder {
if (isPressStartSignal(prevState) && signal === LONG_PRESS_DETECTED) {
const { onLongPress } = this._config;
if (onLongPress != null) {
// Long press is not supported for keyboards because 'click' can be dispatched
// immediately (and multiple times) after 'keydown'.
if (onLongPress != null && event.nativeEvent.key == null) {
onLongPress(event);
this._longPressDispatched = true;
}
@@ -10,8 +10,10 @@
'use strict';
import PressResponder, { type EventHandlers, type PressResponderConfig } from './index';
import { useEffect, useRef } from 'react';
import type { EventHandlers, PressResponderConfig } from './PressResponder';
import PressResponder from './PressResponder';
import { useDebugValue, useEffect, useRef } from 'react';
export default function usePressEvents(hostRef: any, config: PressResponderConfig): EventHandlers {
const pressResponderRef = useRef<?PressResponder>(null);
@@ -33,5 +35,7 @@ export default function usePressEvents(hostRef: any, config: PressResponderConfi
};
}, [pressResponder]);
useDebugValue(config);
return pressResponder.getEventHandlers();
}
+15
View File
@@ -0,0 +1,15 @@
/**
* Copyright (c) Nicolas Gallagher
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export default function isLink(node: HTMLElement) {
return (
(node.nodeName === 'A' && node.getAttribute('href') != null) ||
node.getAttribute('role') === 'link'
);
}