Skip to content

Commit

Permalink
Support onPress/onLongPress in usePressableState (#1061)
Browse files Browse the repository at this point in the history
* Change files

* remove unused import

* reorder to hover/focus/press
  • Loading branch information
Saadnajmi authored Oct 12, 2021
1 parent 629d3e9 commit 8533954
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Support onPress/onLongPress in usePressableState",
"packageName": "@fluentui-react-native/interactive-hooks",
"email": "[email protected]",
"dependentChangeType": "patch"
}
75 changes: 0 additions & 75 deletions packages/utils/interactive-hooks/etc/interactive-hooks.api.md

This file was deleted.

71 changes: 45 additions & 26 deletions packages/utils/interactive-hooks/src/useAsPressable.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { PressableProps, Platform } from 'react-native';
import { PressableProps } from 'react-native';
import { PressableFocusProps, PressableHoverProps, PressablePressProps } from './Pressability/Pressability.types';
import {
IPressableHooks,
Expand Down Expand Up @@ -73,6 +73,16 @@ function useFocusHelper(props: PressableFocusProps): [PressableFocusProps, IFocu
function usePressHelper(props: PressablePressProps): [PressablePressProps, IPressState] {
const [pressState, setPressState] = React.useState({ pressed: false });

const onPress = React.useCallback(
(e) => {
setPressState({ pressed: true });
if (props.onPress) {
props.onPress(e);
}
},
[setPressState, props.onPress],
);

const onPressIn = React.useCallback(
(e) => {
setPressState({ pressed: true });
Expand All @@ -92,27 +102,17 @@ function usePressHelper(props: PressablePressProps): [PressablePressProps, IPres
},
[setPressState, props.onPressOut],
);
return [{ onPressIn, onPressOut }, pressState];
}

/**
* useAsPressable wraps the usePressability hook that will be available in RN 0.63 and beyond. Once this library is on a recent enough
* version of react-native this implementation can switch to using the official version.
*
* The useAsPressable hook adds a simple state change function for listening to hover, press, and focus events on the base pressability implementation
* @param props - input props for the component, mixed in with pressable and pressability options
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export function useAsPressable<T extends object>(props: IWithPressableOptions<T>): IPressableHooks<T> {
const [hoverProps, hoverState] = useHoverHelper(props);
const [focusProps, focusState] = useFocusHelper(props);
const [pressProps, pressState] = usePressHelper(props);
const pressabilityProps = usePressability({ ...props, ...hoverProps, ...focusProps, ...pressProps });

return {
props: { ...props, ...pressabilityProps },
state: { ...hoverState, ...pressState, ...focusState },
};
const onLongPress = React.useCallback(
(e) => {
setPressState({ pressed: true });
if (props.onLongPress) {
props.onLongPress(e);
}
},
[setPressState, props.onLongPress],
);
return [{ onPress, onPressIn, onPressOut, onLongPress }, pressState];
}

/**
Expand Down Expand Up @@ -148,6 +148,26 @@ export function useHoverState<T extends object>(props: IWithPressableOptions<T>)
return [{ ...props, ...usePressability({ ...props, ...hoverProps }) }, hoverState];
}

/**
* useAsPressable wraps the usePressability hook that will be available in RN 0.63 and beyond. Once this library is on a recent enough
* version of react-native this implementation can switch to using the official version.
*
* The useAsPressable hook adds a simple state change function for listening to hover, press, and focus events on the base pressability implementation
* @param props - input props for the component, mixed in with pressable and pressability options
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export function useAsPressable<T extends object>(props: IWithPressableOptions<T>): IPressableHooks<T> {
const [hoverProps, hoverState] = useHoverHelper(props);
const [focusProps, focusState] = useFocusHelper(props);
const [pressProps, pressState] = usePressHelper(props);
const pressabilityProps = usePressability({ ...props, ...hoverProps, ...focusProps, ...pressProps });

return {
props: { ...props, ...pressabilityProps },
state: { ...hoverState, ...focusState, ...pressState },
};
}

/**
* This routine hooks the props to pass to a Pressable component to obtain the current state of the Pressable as well as generating
* state change updates when those props change. This allows a parent component to control the render of the whole component rather than having
Expand All @@ -157,11 +177,10 @@ export function useHoverState<T extends object>(props: IWithPressableOptions<T>)
* @returns - modified props to pass into the Pressable as well as the current state with regards to hover, focus, and press
*/
export function usePressableState(props: PressablePropsExtended): { props: PressableProps; state: IPressableState } {
const { onPressIn, onPressOut, onHoverIn, onHoverOut, onFocus, onBlur, ...rest } = props;
const { onPress, onPressIn, onPressOut, onLongPress, onHoverIn, onHoverOut, onFocus, onBlur, ...rest } = props;
const [hoverProps, hoverState] = useHoverHelper({ onHoverIn, onHoverOut });
const [focusProps, focusState] = useFocusHelper({ onFocus, onBlur });
const [pressProps, pressState] = usePressHelper({ onPressIn, onPressOut });
const platformSupportsHover = Platform.OS !== 'android' && Platform.OS !== 'ios';
const [hoverProps, hoverState] = platformSupportsHover ? useHoverHelper({ onHoverIn, onHoverOut }) : [{}, {}];
const [pressProps, pressState] = usePressHelper({ onPress, onPressIn, onPressOut, onLongPress });

return { props: { ...rest, ...focusProps, ...pressProps, ...hoverProps }, state: { ...focusState, ...pressState, ...hoverState } };
return { props: { ...hoverProps, ...focusProps, ...pressProps, ...rest }, state: { ...hoverState, ...focusState, ...pressState } };
}

0 comments on commit 8533954

Please sign in to comment.