Skip to content

Commit

Permalink
chore: remove hover effect & add cursor: pointer (#122)
Browse files Browse the repository at this point in the history
* chore: remove hover effect

* fix: set cursor pointer by default, update tests

* feat(iOS): Implement cursor style prop

# Conflicts:
#	packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts

---------

Co-authored-by: Saad Najmi <sanajmi@microsoft.com>
# Conflicts:
#	packages/react-native/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap
#	packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js
#	packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js
  • Loading branch information
okwasniewski committed Jun 24, 2024
1 parent 45bb0c8 commit e10134e
Show file tree
Hide file tree
Showing 27 changed files with 402 additions and 164 deletions.
27 changes: 12 additions & 15 deletions packages/react-native/Libraries/Components/Pressable/Pressable.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import type {
AccessibilityState,
AccessibilityValue,
} from '../View/ViewAccessibility';
import type {HoverEffect} from '../View/ViewPropTypes';

import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
import usePressability from '../../Pressability/usePressability';
import {type RectOrSize} from '../../StyleSheet/Rect';
import StyleSheet from '../../StyleSheet/StyleSheet';
import useMergeRefs from '../../Utilities/useMergeRefs';
import View from '../View/View';
import useAndroidRippleForView, {
Expand All @@ -33,18 +33,12 @@ import useAndroidRippleForView, {
import * as React from 'react';
import {useImperativeHandle, useMemo, useRef, useState} from 'react';

const defaultHoverEffect: HoverEffect = 'highlight';

type ViewStyleProp = $ElementType<React.ElementConfig<typeof View>, 'style'>;

export type StateCallbackType = $ReadOnly<{|
pressed: boolean,
|}>;

type VisionOSProps = $ReadOnly<{|
visionos_hoverEffect?: ?HoverEffect,
|}>;

type Props = $ReadOnly<{|
/**
* Accessibility.
Expand Down Expand Up @@ -200,10 +194,6 @@ type Props = $ReadOnly<{|
* https://github.com/facebook/react-native/issues/34424
*/
'aria-label'?: ?string,
/**
* Props needed for visionOS.
*/
...VisionOSProps,
|}>;

/**
Expand Down Expand Up @@ -243,7 +233,6 @@ function Pressable(props: Props, forwardedRef): React.Node {
style,
testOnly_pressed,
unstable_pressDelay,
visionos_hoverEffect = defaultHoverEffect,
...restProps
} = props;

Expand Down Expand Up @@ -352,15 +341,23 @@ function Pressable(props: Props, forwardedRef): React.Node {
{...restPropsWithDefaults}
{...eventHandlers}
ref={mergedRef}
style={typeof style === 'function' ? style({pressed}) : style}
collapsable={false}
visionos_hoverEffect={visionos_hoverEffect}>
style={[
styles.pressable,
typeof style === 'function' ? style({pressed}) : style,
]}
collapsable={false}>
{typeof children === 'function' ? children({pressed}) : children}
{__DEV__ ? <PressabilityDebugView color="red" hitSlop={hitSlop} /> : null}
</View>
);
}

const styles = StyleSheet.create({
pressable: {
cursor: 'pointer',
},
});

function usePressState(forcePressed: boolean): [boolean, (boolean) => void] {
const [pressed, setPressed] = useState(false);
return [pressed || forcePressed, setPressed];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ exports[`<Pressable /> should render as expected: should deep render when mocked
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -67,6 +75,14 @@ exports[`<Pressable /> should render as expected: should deep render when not mo
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -115,6 +131,14 @@ exports[`<Pressable disabled={true} /> should be disabled when disabled is true:
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -151,6 +175,14 @@ exports[`<Pressable disabled={true} /> should be disabled when disabled is true:
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -203,6 +235,14 @@ exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disable
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -239,6 +279,14 @@ exports[`<Pressable disabled={true} accessibilityState={{}} /> should be disable
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -293,6 +341,14 @@ exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> shou
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -329,6 +385,14 @@ exports[`<Pressable disabled={true} accessibilityState={{checked: true}} /> shou
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -391,6 +455,14 @@ exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> sh
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down Expand Up @@ -427,6 +499,14 @@ exports[`<Pressable disabled={true} accessibilityState={{disabled: false}} /> sh
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"cursor": "pointer",
},
undefined,
]
}
>
<View />
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*/

import type {ColorValue} from '../../StyleSheet/StyleSheet';
import type {HoverEffect} from '../View/ViewPropTypes';
import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';

import View from '../../Components/View/View';
Expand All @@ -33,15 +32,10 @@ type IOSProps = $ReadOnly<{|
hasTVPreferredFocus?: ?boolean,
|}>;

type VisionOSProps = $ReadOnly<{|
hoverEffect?: ?HoverEffect,
|}>;

type Props = $ReadOnly<{|
...React.ElementConfig<TouchableWithoutFeedback>,
...AndroidProps,
...IOSProps,
...VisionOSProps,

activeOpacity?: ?number,
underlayColor?: ?ColorValue,
Expand Down Expand Up @@ -335,10 +329,13 @@ class TouchableHighlight extends React.Component<Props, State> {
accessibilityElementsHidden={
this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden
}
style={StyleSheet.compose(
this.props.style,
this.state.extraStyles?.underlay,
)}
style={[
styles.touchable,
StyleSheet.compose(
this.props.style,
this.state.extraStyles?.underlay,
),
]}
onLayout={this.props.onLayout}
hitSlop={this.props.hitSlop}
hasTVPreferredFocus={this.props.hasTVPreferredFocus}
Expand All @@ -347,7 +344,6 @@ class TouchableHighlight extends React.Component<Props, State> {
nextFocusLeft={this.props.nextFocusLeft}
nextFocusRight={this.props.nextFocusRight}
nextFocusUp={this.props.nextFocusUp}
visionos_hoverEffect={this.props.hoverEffect}
focusable={
this.props.focusable !== false && this.props.onPress !== undefined
}
Expand Down Expand Up @@ -386,6 +382,12 @@ class TouchableHighlight extends React.Component<Props, State> {
}
}

const styles = StyleSheet.create({
touchable: {
cursor: 'pointer',
},
});

const Touchable = (React.forwardRef((props, hostRef) => (
<TouchableHighlight {...props} hostRef={hostRef} />
)): React.AbstractComponent<
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type * as React from 'react';
import {Constructor} from '../../../types/private/Utilities';
import {TimerMixin} from '../../../types/private/TimerMixin';
import {NativeMethods} from '../../../types/public/ReactNativeTypes';
import {HoverEffect, TVParallaxProperties} from '../View/ViewPropTypes';
import {TVParallaxProperties} from '../View/ViewPropTypes';
import {TouchableMixin} from './Touchable';
import {TouchableWithoutFeedbackProps} from './TouchableWithoutFeedback';

Expand Down Expand Up @@ -86,11 +86,6 @@ export interface TouchableOpacityProps
* @platform android
*/
tvParallaxProperties?: TVParallaxProperties | undefined;

/**
* Hover style to apply to the view. Only supported on visionOS.
*/
visionos_hoverEffect?: HoverEffect | undefined;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
*/

import type {ViewStyleProp} from '../../StyleSheet/StyleSheet';
import type {HoverEffect} from '../View/ViewPropTypes';
import typeof TouchableWithoutFeedback from './TouchableWithoutFeedback';

import Animated from '../../Animated/Animated';
Expand All @@ -19,11 +18,10 @@ import Pressability, {
} from '../../Pressability/Pressability';
import {PressabilityDebugView} from '../../Pressability/PressabilityDebug';
import flattenStyle from '../../StyleSheet/flattenStyle';
import StyleSheet from '../../StyleSheet/StyleSheet';
import Platform from '../../Utilities/Platform';
import * as React from 'react';

const defaultHoverEffect: HoverEffect = 'highlight';

type TVProps = $ReadOnly<{|
hasTVPreferredFocus?: ?boolean,
nextFocusDown?: ?number,
Expand All @@ -33,14 +31,9 @@ type TVProps = $ReadOnly<{|
nextFocusUp?: ?number,
|}>;

type VisionOSProps = $ReadOnly<{|
visionos_hoverEffect?: ?HoverEffect,
|}>;

type Props = $ReadOnly<{|
...React.ElementConfig<TouchableWithoutFeedback>,
...TVProps,
...VisionOSProps,

activeOpacity?: ?number,
style?: ?ViewStyleProp,
Expand Down Expand Up @@ -138,10 +131,6 @@ type State = $ReadOnly<{|
*
*/
class TouchableOpacity extends React.Component<Props, State> {
static defaultProps: {|visionos_hoverEffect: HoverEffect|} = {
visionos_hoverEffect: defaultHoverEffect,
};

state: State = {
anim: new Animated.Value(this._getChildStyleOpacityWithDefault()),
pressability: new Pressability(this._createPressabilityConfig()),
Expand Down Expand Up @@ -287,7 +276,7 @@ class TouchableOpacity extends React.Component<Props, State> {
accessibilityElementsHidden={
this.props['aria-hidden'] ?? this.props.accessibilityElementsHidden
}
style={[this.props.style, {opacity: this.state.anim}]}
style={[styles.touchable, this.props.style, {opacity: this.state.anim}]}
nativeID={this.props.id ?? this.props.nativeID}
testID={this.props.testID}
onLayout={this.props.onLayout}
Expand All @@ -298,7 +287,6 @@ class TouchableOpacity extends React.Component<Props, State> {
nextFocusUp={this.props.nextFocusUp}
hasTVPreferredFocus={this.props.hasTVPreferredFocus}
hitSlop={this.props.hitSlop}
visionos_hoverEffect={this.props.visionos_hoverEffect}
focusable={
this.props.focusable !== false && this.props.onPress !== undefined
}
Expand Down Expand Up @@ -336,6 +324,12 @@ class TouchableOpacity extends React.Component<Props, State> {
}
}

const styles = StyleSheet.create({
touchable: {
cursor: 'pointer',
},
});

const Touchable = (React.forwardRef((props, ref) => (
<TouchableOpacity {...props} hostRef={ref} />
)): React.AbstractComponent<Props, React.ElementRef<typeof Animated.View>>);
Expand Down
Loading

0 comments on commit e10134e

Please sign in to comment.