From 1c0da9a29ae8b8eb2ebab15fcab61e37eee77866 Mon Sep 17 00:00:00 2001 From: Evrim Persembe Date: Sat, 3 Apr 2021 20:45:45 +0300 Subject: [PATCH] Add simultaneous handlers support to make the component usable within a ScrollView (#273) * Set react-native-gesture-handler dependency to ^1.10.0 * Ignore JetBrains IDE settings * Add simultaneousHandlers and onGestureHandlerRef props * Remove onGestureHandlerRef as it turned out it is not necessary * Add simultaneousHandler prop to README --- .gitignore | 1 + README.md | 74 +++++++++++++++++++++++++++------------------------ package.json | 2 +- src/index.tsx | 6 ++++- yarn.lock | 34 ++++++++++++++++++++--- 5 files changed, 76 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index b467792..81f7981 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/**/* /lib coverage/ +.idea diff --git a/README.md b/README.md index fce7169..84f8edb 100644 --- a/README.md +++ b/README.md @@ -31,39 +31,41 @@ yarn add react-native-draggable-flatlist All props are spread onto underlying [FlatList](https://facebook.github.io/react-native/docs/flatlist) -| Name | Type | Description | -| :------------------------- | :---------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `data` | `T[]` | Items to be rendered. | -| `horizontal` | `boolean` | Orientation of list. | -| `renderItem` | `(params: { item: T, index: number, drag: () => void, isActive: boolean}) => JSX.Element` | Call `drag` when the row should become active (i.e. in an `onLongPress` or `onPressIn`). | -| `renderPlaceholder` | `(params: { item: T, index: number }) => React.ReactNode` | Component to be rendered underneath the hovering component | -| `keyExtractor` | `(item: T, index: number) => string` | Unique key for each item | -| `onDragBegin` | `(index: number) => void` | Called when row becomes active. | -| `onRelease` | `(index: number) => void` | Called when active row touch ends. | -| `onDragEnd` | `(params: { data: T[], from: number, to: number }) => void` | Called after animation has completed. Returns updated ordering of `data` | -| `autoscrollThreshold` | `number` | Distance from edge of container where list begins to autoscroll when dragging. | -| `autoscrollSpeed` | `number` | Determines how fast the list autoscrolls. | -| `onRef` | `(ref: React.RefObject>) => void` | Returns underlying Animated FlatList ref. | -| `animationConfig` | `Partial` | Configure list animations. See [reanimated spring config](https://github.com/software-mansion/react-native-reanimated/blob/master/react-native-reanimated.d.ts#L112-L120) | -| `activationDistance` | `number` | Distance a finger must travel before the gesture handler activates. Useful when using a draggable list within a TabNavigator so that the list does not capture navigator gestures. | -| `layoutInvalidationKey` | `string` | Changing this value forces a remeasure of all item layouts. Useful if item size/ordering updates after initial mount. | -| `onScrollOffsetChange` | `(offset: number) => void` | Called with scroll offset. Stand-in for `onScroll`. | -| `onPlaceholderIndexChange` | `(index: number) => void` | Called when the index of the placeholder changes | -| `dragItemOverflow` | `boolean` | If true, dragged item follows finger beyond list boundary. | -| `dragHitSlop` | `object: {top: number, left: number, bottom: number, right: number}` | Enables control over what part of the connected view area can be used to begin recognizing the gesture. Numbers need to be non-positive (only possible to reduce responsive area). | -| `debug` | `boolean` | Enables debug logging and animation debugger. | -| `containerStyle` | `StyleProp` | Style of the main component. | +| Name | Type | Description | +| :------------------------- | :---------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | `T[]` | Items to be rendered. | +| `horizontal` | `boolean` | Orientation of list. | +| `renderItem` | `(params: { item: T, index: number, drag: () => void, isActive: boolean}) => JSX.Element` | Call `drag` when the row should become active (i.e. in an `onLongPress` or `onPressIn`). | +| `renderPlaceholder` | `(params: { item: T, index: number }) => React.ReactNode` | Component to be rendered underneath the hovering component | +| `keyExtractor` | `(item: T, index: number) => string` | Unique key for each item | +| `onDragBegin` | `(index: number) => void` | Called when row becomes active. | +| `onRelease` | `(index: number) => void` | Called when active row touch ends. | +| `onDragEnd` | `(params: { data: T[], from: number, to: number }) => void` | Called after animation has completed. Returns updated ordering of `data` | +| `autoscrollThreshold` | `number` | Distance from edge of container where list begins to autoscroll when dragging. | +| `autoscrollSpeed` | `number` | Determines how fast the list autoscrolls. | +| `onRef` | `(ref: React.RefObject>) => void` | Returns underlying Animated FlatList ref. | +| `animationConfig` | `Partial` | Configure list animations. See [reanimated spring config](https://github.com/software-mansion/react-native-reanimated/blob/master/react-native-reanimated.d.ts#L112-L120) | +| `activationDistance` | `number` | Distance a finger must travel before the gesture handler activates. Useful when using a draggable list within a TabNavigator so that the list does not capture navigator gestures. | +| `layoutInvalidationKey` | `string` | Changing this value forces a remeasure of all item layouts. Useful if item size/ordering updates after initial mount. | +| `onScrollOffsetChange` | `(offset: number) => void` | Called with scroll offset. Stand-in for `onScroll`. | +| `onPlaceholderIndexChange` | `(index: number) => void` | Called when the index of the placeholder changes | +| `dragItemOverflow` | `boolean` | If true, dragged item follows finger beyond list boundary. | +| `dragHitSlop` | `object: {top: number, left: number, bottom: number, right: number}` | Enables control over what part of the connected view area can be used to begin recognizing the gesture. Numbers need to be non-positive (only possible to reduce responsive area). | +| `debug` | `boolean` | Enables debug logging and animation debugger. | +| `containerStyle` | `StyleProp` | Style of the main component. | +| `simultaneousHandlers` | `React.Ref` or `React.Ref[]` | References to other gesture handlers, mainly useful when using this component within a `ScrollView`. See [Cross handler interactions](https://docs.swmansion.com/react-native-gesture-handler/docs/interactions/). | ## Example + Example snack: https://snack.expo.io/@computerjazz/rndfl-example
Example snack with scale effect on hover: https://snack.expo.io/@computerjazz/rndfl-dragwithhovereffect ```typescript -import React, { useState, useCallback } from 'react'; -import { View, TouchableOpacity, Text } from 'react-native'; +import React, { useState, useCallback } from "react"; +import { View, TouchableOpacity, Text } from "react-native"; import DraggableFlatList, { - RenderItemParams, -} from 'react-native-draggable-flatlist'; + RenderItemParams +} from "react-native-draggable-flatlist"; const NUM_ITEMS = 10; @@ -78,7 +80,7 @@ const exampleData: Item[] = [...Array(20)].map((d, index) => { return { key: `item-${backgroundColor}`, label: String(index), - backgroundColor, + backgroundColor }; }); @@ -97,17 +99,19 @@ function Example() { + onLongPress={drag} + > + fontWeight: "bold", + color: "white", + fontSize: 32 + }} + > {item.label} diff --git a/package.json b/package.json index 3c0b83c..e119a25 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "pretty-quick": "^2.0.1", "react": "^16.13.1", "react-native": "^0.61.5", - "react-native-gesture-handler": "^1.5.3", + "react-native-gesture-handler": "^1.10.0", "react-native-reanimated": "^1.13.0", "react-test-renderer": "~16.11.0", "typescript": "^3.7.3" diff --git a/src/index.tsx b/src/index.tsx index 19d90cd..ce8511c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -113,6 +113,7 @@ export type DraggableFlatListProps = Modify< onPlaceholderIndexChange?: (placeholderIndex: number) => void; containerStyle?: StyleProp; dragItemOverflow?: boolean; + simultaneousHandlers?: React.Ref | React.Ref[]; } & Partial >; @@ -1002,7 +1003,8 @@ class DraggableFlatList extends React.Component< onScrollOffsetChange, renderPlaceholder, onPlaceholderIndexChange, - containerStyle + containerStyle, + simultaneousHandlers } = this.props; const { hoverComponent } = this.state; @@ -1019,6 +1021,7 @@ class DraggableFlatList extends React.Component< hitSlop={dragHitSlop} onGestureEvent={this.onPanGestureEvent} onHandlerStateChange={this.onPanStateChange} + simultaneousHandlers={simultaneousHandlers} {...dynamicProps} > extends React.Component< keyExtractor={this.keyExtractor} onScroll={this.onScroll} scrollEventThrottle={1} + simultaneousHandlers={simultaneousHandlers} /> {!!hoverComponent && this.renderHoverComponent()} diff --git a/yarn.lock b/yarn.lock index 069bc14..30447c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2331,6 +2331,13 @@ create-react-class@^15.6.3: loose-envify "^1.3.1" object-assign "^4.1.1" +cross-fetch@^3.0.4: + version "3.0.6" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" + integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2877,6 +2884,19 @@ fbjs@^1.0.0: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +fbjs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.0.tgz#0907067fb3f57a78f45d95f1eacffcacd623c165" + integrity sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg== + dependencies: + cross-fetch "^3.0.4" + fbjs-css-vars "^1.0.0" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.18" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -4848,6 +4868,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -5471,12 +5496,13 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== -react-native-gesture-handler@^1.5.3: - version "1.8.0" - resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.8.0.tgz#18f61f51da50320f938957b0ee79bc58f47449dc" - integrity sha512-E2FZa0qZ5Bi0Z8Jg4n9DaFomHvedSjwbO2DPmUUHYRy1lH2yxXUpSrqJd6yymu+Efzmjg2+JZzsjFYA2Iq8VEQ== +react-native-gesture-handler@^1.10.0: + version "1.10.3" + resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.10.3.tgz#942bbf2963bbf49fa79593600ee9d7b5dab3cfc0" + integrity sha512-cBGMi1IEsIVMgoox4RvMx7V2r6bNKw0uR1Mu1o7NbuHS6BRSVLq0dP34l2ecnPlC+jpWd3le6Yg1nrdCjby2Mw== dependencies: "@egjs/hammerjs" "^2.0.17" + fbjs "^3.0.0" hoist-non-react-statics "^3.3.0" invariant "^2.2.4" prop-types "^15.7.2"