[add] Pressable support for hover callbacks

Add 'onHoverIn' and 'onHoverOut' props to Pressable.

Fix #1804
This commit is contained in:
Nicolas Gallagher
2021-02-05 15:55:08 -08:00
parent d6d28a4886
commit 683962b961
3 changed files with 24 additions and 3 deletions
@@ -88,11 +88,15 @@ describe('components/Pressable', () => {
test('hover interaction', () => { test('hover interaction', () => {
let container; let container;
const onHoverIn = jest.fn();
const onHoverOut = jest.fn();
const ref = React.createRef(); const ref = React.createRef();
act(() => { act(() => {
({ container } = render( ({ container } = render(
<Pressable <Pressable
children={({ hovered }) => (hovered ? <div data-testid="hover-content" /> : null)} children={({ hovered }) => (hovered ? <div data-testid="hover-content" /> : null)}
onHoverIn={onHoverIn}
onHoverOut={onHoverOut}
ref={ref} ref={ref}
style={({ hovered }) => [hovered && { outline: 'hover-ring' }]} style={({ hovered }) => [hovered && { outline: 'hover-ring' }]}
/> />
@@ -103,10 +107,12 @@ describe('components/Pressable', () => {
act(() => { act(() => {
target.pointerover(); target.pointerover();
}); });
expect(onHoverIn).toBeCalled();
expect(container.firstChild).toMatchSnapshot(); expect(container.firstChild).toMatchSnapshot();
act(() => { act(() => {
target.pointerout(); target.pointerout();
}); });
expect(onHoverOut).toBeCalled();
expect(container.firstChild).toMatchSnapshot(); expect(container.firstChild).toMatchSnapshot();
}); });
+17 -2
View File
@@ -10,6 +10,7 @@
'use strict'; 'use strict';
import type { HoverEventsConfig } from '../../modules/useHover';
import type { PressResponderConfig } from '../../modules/usePressEvents/PressResponder'; import type { PressResponderConfig } from '../../modules/usePressEvents/PressResponder';
import type { ViewProps } from '../View'; import type { ViewProps } from '../View';
@@ -51,6 +52,10 @@ type Props = $ReadOnly<{|
onBlur?: $PropertyType<ViewProps, 'onBlur'>, onBlur?: $PropertyType<ViewProps, 'onBlur'>,
// Called when the view is focused // Called when the view is focused
onFocus?: $PropertyType<ViewProps, 'onFocus'>, onFocus?: $PropertyType<ViewProps, 'onFocus'>,
// Called when the view is hovered
onHoverIn?: $PropertyType<HoverEventsConfig, 'onHoverStart'>,
// Called when the view is no longer hovered
onHoverOut?: $PropertyType<HoverEventsConfig, 'onHoverEnd'>,
// Called when this view's layout changes // Called when this view's layout changes
onLayout?: $PropertyType<ViewProps, 'onLayout'>, onLayout?: $PropertyType<ViewProps, 'onLayout'>,
// Called when a long-tap gesture is detected. // Called when a long-tap gesture is detected.
@@ -68,6 +73,7 @@ type Props = $ReadOnly<{|
/** /**
* Used only for documentation or testing (e.g. snapshot testing). * Used only for documentation or testing (e.g. snapshot testing).
*/ */
testOnly_hovered?: ?boolean,
testOnly_pressed?: ?boolean testOnly_pressed?: ?boolean
|}>; |}>;
@@ -85,17 +91,20 @@ function Pressable(props: Props, forwardedRef): React.Node {
focusable, focusable,
onBlur, onBlur,
onFocus, onFocus,
onHoverIn,
onHoverOut,
onLongPress, onLongPress,
onPress, onPress,
onPressMove, onPressMove,
onPressIn, onPressIn,
onPressOut, onPressOut,
style, style,
testOnly_hovered,
testOnly_pressed, testOnly_pressed,
...rest ...rest
} = props; } = props;
const [hovered, setHovered] = useForceableState(false); const [hovered, setHovered] = useForceableState(testOnly_hovered === true);
const [focused, setFocused] = useForceableState(false); const [focused, setFocused] = useForceableState(false);
const [pressed, setPressed] = useForceableState(testOnly_pressed === true); const [pressed, setPressed] = useForceableState(testOnly_pressed === true);
@@ -131,7 +140,13 @@ function Pressable(props: Props, forwardedRef): React.Node {
const pressEventHandlers = usePressEvents(hostRef, pressConfig); const pressEventHandlers = usePressEvents(hostRef, pressConfig);
useHover(hostRef, { contain: true, disabled, onHoverChange: setHovered }); useHover(hostRef, {
contain: true,
disabled,
onHoverChange: setHovered,
onHoverStart: onHoverIn,
onHoverEnd: onHoverOut
});
const interactionState = { hovered, focused, pressed }; const interactionState = { hovered, focused, pressed };
+1 -1
View File
@@ -15,7 +15,7 @@ import useLayoutEffect from '../useLayoutEffect';
* Types * Types
*/ */
type HoverEventsConfig = { export type HoverEventsConfig = {
contain?: ?boolean, contain?: ?boolean,
disabled?: ?boolean, disabled?: ?boolean,
onHoverStart?: ?(e: any) => void, onHoverStart?: ?(e: any) => void,