Skip to content

Commit 329b2b2

Browse files
authored
Fix Pressable styling by removing unnecessary wrapping View (#3087)
## Description This PR removes outer `View` from `Pressable` which was previously used for applying props, which were otherwise unavailable on `NativeButton`. All such props have been either manually implemented, or have turned out to be available to use directly in `NativeButton`, so the outer `View` can be safely removed. closes #3085 ## Test plan - paste the provided code in place of the `EmptyExample` - open the `EmptyExample` - see how both the boxes on the left, and the ones on the right behave identically ## Verifying accessibility - platform specific setup - `[iOS]` Turn on `smart inverted colors mode` - `[Android]` Turn on `talkback` - paste the provided code in place of the `EmptyExample` - open the `EmptyExample` - platform specific steps - `[iOS]` See how the `Nested box model styling` section has regular colors - `[Android]` Press the `Nested box model styling` and hear how it says `Accessibility is working` note: Most accessibility styles are not implemented on `web`, but you can verify that accessibility is working on web by inspecting the `Pressable` and looking for `role="button"` prop in the HTML, it is an accessibility prop that i found to be working on web. ## Code <details> <summary> Collapsed code </summary> ```tsx import React from 'react'; import { StyleSheet, Text, View, Pressable as RNPressable } from 'react-native'; import { Pressable as GHPressable, PressableProps, } from 'react-native-gesture-handler'; function Pressables(props: PressableProps) { const onPressInGH = () => console.log('GH press'); const onPressInRN = () => console.log('RN press'); return ( <View style={styles.container}> <GHPressable {...(props as any)} onPressIn={onPressInGH} style={[styles.pressable, props.style]}> {props.children ?? <Text>Gesture Handler!</Text>} </GHPressable> <RNPressable {...(props as any)} onPressIn={onPressInRN} style={[styles.pressable, props.style]}> {props.children ?? <Text>React Native!</Text>} </RNPressable> </View> ); } export default function EmptyExample() { return ( <View style={styles.multirow}> <Text style={styles.header}>Padding</Text> <Pressables style={{ padding: 16 }} /> <Text style={styles.header}>GH nested pressable</Text> <Pressables style={{ flex: 1, backgroundColor: 'plum' }}> <GHPressable style={{ backgroundColor: 'orange', }}> <Text>Gesture Handler</Text> </GHPressable> </Pressables> <Text style={styles.header}>RN nested pressable</Text> <Pressables style={{ flex: 1, backgroundColor: 'plum' }}> <RNPressable style={{ backgroundColor: 'orange', }}> <Text>React Native</Text> </RNPressable> </Pressables> <Text style={styles.header}>2 nested pressables</Text> <Pressables style={{ flex: 1, backgroundColor: 'plum', flexDirection: 'row' }}> <GHPressable style={{ backgroundColor: 'pink', }}> <Text style={{ padding: 8 }}>GH</Text> </GHPressable> <RNPressable style={{ backgroundColor: 'orange', }}> <Text style={{ padding: 8 }}>RN</Text> </RNPressable> </Pressables> <Text style={styles.header}>Nested box model styling</Text> <Pressables accessibilityIgnoresInvertColors> <View style={{ backgroundColor: 'orange', padding: 8, margin: 8 }}> <View style={{ backgroundColor: 'plum', margin: 8 }}> <Text>Hello World!</Text> </View> </View> </Pressables> <Text style={styles.header}>Flex view in a fixed size Pressable</Text> <Pressables style={{ width: 100, height: 100 }}> <View style={styles.textWrapper}> <Text>Pressable!</Text> </View> </Pressables> <Text style={styles.header}>Flex view in a formless size Pressable</Text> <Pressables> <View style={styles.textWrapper}> <Text>Pressable!</Text> </View> </Pressables> <Text style={styles.header}>Standalone pressable</Text> <Pressables> <Text>Pressable!</Text> </Pressables> </View> ); } const styles = StyleSheet.create({ header: { fontSize: 16, fontWeight: 'bold', textAlign: 'center', }, multirow: { flex: 1, flexDirection: 'column', }, container: { flexDirection: 'row', justifyContent: 'space-around', gap: 30, margin: 30, marginTop: 5, }, pressable: { backgroundColor: 'tomato', borderWidth: 1, maxWidth: '30%', }, textWrapper: { flex: 1, justifyContent: 'center', alignItems: 'center', }, }); ``` </details>
1 parent f6fcfc0 commit 329b2b2

File tree

2 files changed

+17
-76
lines changed

2 files changed

+17
-76
lines changed

src/components/Pressable/Pressable.tsx

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
View,
1010
ViewStyle,
1111
processColor,
12-
StyleSheet,
1312
} from 'react-native';
1413
import NativeButton from '../GestureHandlerButton';
1514
import {
@@ -18,7 +17,6 @@ import {
1817
isTouchWithinInset,
1918
gestureTouchToPressableEvent,
2019
addInsets,
21-
splitStyles,
2220
} from './utils';
2321
import { PressabilityDebugView } from '../../handlers/PressabilityDebugView';
2422
import { GestureTouchEvent } from '../../handlers/gestureHandlerCommon';
@@ -386,33 +384,22 @@ export default function Pressable(props: PressableProps) {
386384
? children({ pressed: pressedState })
387385
: children;
388386

389-
const flattenedStyles = StyleSheet.flatten(styleProp ?? {});
390-
391-
const [innerStyles, outerStyles] = splitStyles(flattenedStyles);
392-
393387
return (
394-
<View {...remainingProps} style={outerStyles}>
395-
<GestureDetector gesture={gesture}>
396-
<NativeButton
397-
ref={pressableRef}
398-
hitSlop={appliedHitSlop}
399-
enabled={isPressableEnabled}
400-
touchSoundDisabled={android_disableSound ?? undefined}
401-
rippleColor={processColor(
402-
android_ripple?.color ?? defaultRippleColor
403-
)}
404-
rippleRadius={android_ripple?.radius ?? undefined}
405-
style={[
406-
{ width: '100%', height: '100%' },
407-
pointerStyle,
408-
innerStyles,
409-
]}>
410-
{childrenProp}
411-
{__DEV__ ? (
412-
<PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />
413-
) : null}
414-
</NativeButton>
415-
</GestureDetector>
416-
</View>
388+
<GestureDetector gesture={gesture}>
389+
<NativeButton
390+
{...remainingProps}
391+
ref={pressableRef}
392+
hitSlop={appliedHitSlop}
393+
enabled={isPressableEnabled}
394+
touchSoundDisabled={android_disableSound ?? undefined}
395+
rippleColor={processColor(android_ripple?.color ?? defaultRippleColor)}
396+
rippleRadius={android_ripple?.radius ?? undefined}
397+
style={[pointerStyle, styleProp]}>
398+
{childrenProp}
399+
{__DEV__ ? (
400+
<PressabilityDebugView color="red" hitSlop={normalizedHitSlop} />
401+
) : null}
402+
</NativeButton>
403+
</GestureDetector>
417404
);
418405
}

src/components/Pressable/utils.ts

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Insets, ViewStyle } from 'react-native';
1+
import { Insets } from 'react-native';
22
import { LongPressGestureHandlerEventPayload } from '../../handlers/GestureHandlerEventPayload';
33
import {
44
TouchData,
@@ -125,56 +125,10 @@ const gestureTouchToPressableEvent = (
125125
};
126126
};
127127

128-
type StylePropKeys = (keyof ViewStyle)[];
129-
130-
// Source:
131-
// - From ViewStyle extracted FlexStyle sub-interface which contains all of the box-model manipulating props.
132-
// - From FlexStyle handpicked those styles, which act on the inner part of the box-model.
133-
const innerStyleKeys = new Set([
134-
'alignContent',
135-
'alignItems',
136-
'flexBasis',
137-
'flexDirection',
138-
'flexWrap',
139-
'rowGap',
140-
'gap',
141-
'columnGap',
142-
'justifyContent',
143-
'overflow',
144-
'padding',
145-
'paddingBottom',
146-
'paddingEnd',
147-
'paddingHorizontal',
148-
'paddingLeft',
149-
'paddingRight',
150-
'paddingStart',
151-
'paddingTop',
152-
'paddingVertical',
153-
'start',
154-
'end',
155-
'direction', // iOS only
156-
] as StylePropKeys);
157-
158-
const splitStyles = (from: ViewStyle): [ViewStyle, ViewStyle] => {
159-
const outerStyles: Record<string, unknown> = {};
160-
const innerStyles: Record<string, unknown> = {};
161-
162-
for (const key in from) {
163-
if (innerStyleKeys.has(key as keyof ViewStyle)) {
164-
innerStyles[key] = from[key as keyof ViewStyle];
165-
} else {
166-
outerStyles[key] = from[key as keyof ViewStyle];
167-
}
168-
}
169-
170-
return [innerStyles, outerStyles];
171-
};
172-
173128
export {
174129
numberAsInset,
175130
addInsets,
176131
isTouchWithinInset,
177132
gestureToPressableEvent,
178133
gestureTouchToPressableEvent,
179-
splitStyles,
180134
};

0 commit comments

Comments
 (0)