hyochan / react-native-masonry-list

The Masonry List implementation which has similar implementation as the `FlatList` in React Native
MIT License
393 stars 55 forks source link

improvement: avoid two taps requirement for android #51

Closed lucianomlima closed 1 year ago

lucianomlima commented 1 year ago

Description

This PR adds keyboardShouldPersistTaps with handled as default value to improve usability in some cases like having focus in an input, but needs two taps to interact with pressable components like buttons, sliders and switchs.

To clarify the issue, I record 2 videos:

without keyboardShouldPersistTaps

We needs two taps, 1 for keyboard dismiss and another one to interact with pressable.

https://user-images.githubusercontent.com/1580205/194769387-10df1f44-9201-4ae1-a752-83b308b02227.mp4

with keyboardShouldPersistTaps as handled

Here we need only 1 tap to interact with pressable.

https://user-images.githubusercontent.com/1580205/194769393-24305f8b-9528-410c-adcf-e0544e1fedb9.mp4

Related Issues

resolves #29

Tests

Don't need new tests[^1], only a snapshot update. But to tests in your computer, you can use the MansoryExample App.tsx patch below:

MasonryExample/src/App.tsx.patch ```diff diff --git a/MasonryExample/src/App.tsx b/MasonryExample/src/App.tsx index ef22d5e..254921b 100644 --- a/MasonryExample/src/App.tsx +++ b/MasonryExample/src/App.tsx @@ -1,15 +1,19 @@ import { + Alert, Image, + Pressable, SafeAreaView, StatusBar, StyleProp, + StyleSheet, Text, + TextInput, View, ViewStyle, useColorScheme, } from 'react-native'; // eslint-disable-next-line @typescript-eslint/no-use-before-define -import React, {FC, ReactElement, useMemo} from 'react'; +import React, {useMemo, useState} from 'react'; import {Colors} from 'react-native/Libraries/NewAppScreen'; import MasonryList from '@react-native-seoul/masonry-list'; @@ -19,6 +23,7 @@ interface Furniture { id: string; imgURL: string; text: string; + pressable?: boolean; } const data: Furniture[] = [ @@ -39,12 +44,14 @@ const data: Furniture[] = [ imgURL: 'https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/leverette-fabric-queen-upholstered-platform-bed-1594829293.jpg', text: 'Leverette Upholstered Platform Bed', + pressable: true, }, { id: 'id126', imgURL: 'https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/briget-side-table-1582143245.jpg?crop=1.00xw:0.770xh;0,0.129xh&resize=768:*', text: 'Briget Accent Table', + pressable: true, }, { id: 'id127', @@ -63,6 +70,7 @@ const data: Furniture[] = [ imgURL: 'https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/goodee-ecobirdy-charlie-chairs-1594834221.jpg?crop=1xw:1xh;center,top&resize=768:*', text: 'Ecobirdy Charlie Chair', + pressable: true, }, { id: 'id130', @@ -168,15 +176,32 @@ const data: Furniture[] = [ }, ]; -const FurnitureCard: FC<{item: Furniture; style: StyleProp}> = ({ +const FurnitureCard = ({ item, style, -}) => { +}: { + item: Furniture; + style: StyleProp; +}): JSX.Element => { const randomBool = useMemo(() => Math.random() < 0.5, []); const {theme} = useTheme(); + const Wrapper = item.pressable ? Pressable : View; return ( - + + Alert.alert('Item pressed:', item.text, undefined, {cancelable: true}) + } + style={[ + { + marginTop: 12, + flex: 1, + backgroundColor: item.pressable ? '#DFDFDF' : '#FFF', + }, + style, + ]} + > }> = ({ {item.text} - + ); }; -const App: FC = () => { +const App = (): JSX.Element => { + const [text, onChangeText] = useState(''); const isDarkMode = useColorScheme() === 'dark'; const backgroundStyle = { @@ -205,13 +232,7 @@ const App: FC = () => { flex: 1, }; - const renderItem = ({ - item, - i, - }: { - item: Furniture; - i: number; - }): ReactElement => { + const renderItem = ({item, i}: {item: Furniture; i: number}): JSX.Element => { return ( ); @@ -221,8 +242,10 @@ const App: FC = () => { item.id} - ListHeaderComponent={} + keyboardDismissMode="on-drag" + keyboardShouldPersistTaps="handled" contentContainerStyle={{ paddingHorizontal: 24, alignSelf: 'stretch', @@ -231,8 +254,26 @@ const App: FC = () => { data={data} renderItem={renderItem} /> + ); }; +const styles = StyleSheet.create({ + textInput: { + height: 40, + marginHorizontal: 24, + marginVertical: 12, + borderColor: '#888', + borderRadius: 8, + borderWidth: 1, + padding: 12, + }, +}); export default App; ```

[^1]: I update some tests that don't requires to be async.

Checklist

Before you create this PR confirms that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

lucianomlima commented 1 year ago

@hyochan sorry to get into this, but this year the participation on Hacktoberfest changed a little bit.

YOUR PR/MRS MUST BE IN A REPO TAGGED WITH THE “HACKTOBERFEST” TOPIC, OR HAVE THE “HACKTOBERFEST-ACCEPTED” LABEL.

So, can you please add the hacktoberfest-accepted to the this PR to marked as participating? 🙏

hyochan commented 1 year ago

@hyochan sorry to get into this, but this year the participation on Hacktoberfest changed a little bit.

YOUR PR/MRS MUST BE IN A REPO TAGGED WITH THE “HACKTOBERFEST” TOPIC, OR HAVE THE “HACKTOBERFEST-ACCEPTED” LABEL. So, can you please add the hacktoberfest-accepted to the this PR to marked as participating? 🙏

Just done it! Hope it helps!