diff --git a/DrawerLayout/package.json b/DrawerLayout/package.json
deleted file mode 100644
index 3e0e4a2fac..0000000000
--- a/DrawerLayout/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "main": "../lib/commonjs/components/DrawerLayout",
- "module": "../lib/module/components/DrawerLayout",
- "react-native": "../src/components/DrawerLayout",
- "types": "../lib/typescript/components/DrawerLayout.d.ts"
-}
diff --git a/FabricExample/yarn.lock b/FabricExample/yarn.lock
index e18c7b3a48..127f5befbf 100644
--- a/FabricExample/yarn.lock
+++ b/FabricExample/yarn.lock
@@ -1128,13 +1128,6 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@egjs/hammerjs@^2.0.17":
- version "2.0.17"
- resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
- integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==
- dependencies:
- "@types/hammerjs" "^2.0.36"
-
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -1902,11 +1895,6 @@
dependencies:
"@types/node" "*"
-"@types/hammerjs@^2.0.36":
- version "2.0.45"
- resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.45.tgz#ffa764bb68a66c08db6efb9c816eb7be850577b1"
- integrity sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==
-
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7"
diff --git a/MacOSExample/babel.config.js b/MacOSExample/babel.config.js
index 973c77d95c..85bd7c2187 100644
--- a/MacOSExample/babel.config.js
+++ b/MacOSExample/babel.config.js
@@ -15,8 +15,6 @@ module.exports = {
'../src/components/ReanimatedSwipeable',
'react-native-gesture-handler/ReanimatedDrawerLayout':
'../src/components/ReanimatedDrawerLayout',
- 'react-native-gesture-handler/Swipeable':
- '../src/components/Swipeable',
'react-native-gesture-handler': '../src/index',
},
},
diff --git a/MacOSExample/yarn.lock b/MacOSExample/yarn.lock
index 287bc0af16..3d591749d7 100644
--- a/MacOSExample/yarn.lock
+++ b/MacOSExample/yarn.lock
@@ -1427,13 +1427,6 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@egjs/hammerjs@^2.0.17":
- version "2.0.17"
- resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
- integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==
- dependencies:
- "@types/hammerjs" "^2.0.36"
-
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -2330,11 +2323,6 @@
dependencies:
"@types/node" "*"
-"@types/hammerjs@^2.0.36":
- version "2.0.43"
- resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.43.tgz#8660dd1e0e5fd979395e2f999e670cdb9484d1e9"
- integrity sha512-wqxfwHk83RS7+6OpytGdo5wqkqtvx+bGaIs1Rwm5NrtQHUfL4OgWs/5p0OipmjmT+fexePh37Ek+mqIpdNjQKA==
-
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#fdfdd69fa16d530047d9963635bd77c71a08c068"
diff --git a/Swipeable/package.json b/Swipeable/package.json
deleted file mode 100644
index ed038794ba..0000000000
--- a/Swipeable/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "main": "../lib/commonjs/components/Swipeable",
- "module": "../lib/module/components/Swipeable",
- "react-native": "../src/components/Swipeable",
- "types": "../lib/typescript/components/Swipeable.d.ts"
-}
diff --git a/docs/docs/components/drawer-layout.mdx b/docs/docs/components/drawer-layout.mdx
deleted file mode 100644
index 5652ab1822..0000000000
--- a/docs/docs/components/drawer-layout.mdx
+++ /dev/null
@@ -1,170 +0,0 @@
----
-id: drawer-layout
-title: Drawer Layout
-sidebar_label: DrawerLayout
----
-
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import GifGallery from '@site/components/GifGallery';
-
-This is a cross-platform replacement for React Native's [DrawerLayoutAndroid](http://reactnative.dev/docs/drawerlayoutandroid.html) component. It provides a compatible API but allows for the component to be used on both Android and iOS. Please refer to [React Native docs](http://reactnative.dev/docs/drawerlayoutandroid.html) for the detailed usage for standard parameters.
-
-## Usage:
-
-`DrawerLayout` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way:
-
-```js
-import DrawerLayout from 'react-native-gesture-handler/DrawerLayout';
-```
-
-## Properties:
-
-On top of the standard list of parameters DrawerLayout has an additional set of attributes to customize its behavior. Please refer to the list below:
-
-### `drawerType`
-
-possible values are: `front`, `back` or `slide` (default is `front`). It specifies the way the drawer will be displayed. When set to `front` the drawer will slide in and out along with the gesture and will display on top of the content view. When `back` is used the drawer displays behind the content view and can be revealed with gesture of pulling the content view to the side. Finally `slide` option makes the drawer appear like it is attached to the side of the content view; when you pull both content view and drawer will follow the gesture.
-
-Type `slide`:
-
-
-
-
-
-Type `front`:
-
-
-
-
-
-Type `back`:
-
-
-
-
-
-### `edgeWidth`
-
-number, allows for defining how far from the edge of the content view the gesture should activate.
-
-### `hideStatusBar`
-
-boolean, when set to `true` Drawer component will use [StatusBar](http://reactnative.dev/docs/statusbar.html) API to hide the OS status bar whenever the drawer is pulled or when its in an "open" state.
-
-### `statusBarAnimation`
-
-possible values are: `slide`, `none` or `fade` (defaults to `slide`). Can be used when `hideStatusBar` is set to `true` and will select the animation used for hiding/showing the status bar. See [StatusBar](http://reactnative.dev/docs/statusbar.html#statusbaranimation) documentation for more details.
-
-### `overlayColor`
-
-color (default to `"black"`) of a semi-transparent overlay to be displayed on top of the content view when drawer gets open. A solid color should be used as the opacity is added by the Drawer itself and the opacity of the overlay is animated (from 0% to 70%).
-
-### `renderNavigationView`
-
-function. This attribute is present in the standard implementation already and is one of the required params. Gesture handler version of DrawerLayout make it possible for the function passed as `renderNavigationView` to take an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened). This can be used by the drawer component to animated its children while the drawer is opening or closing.
-
-### `onDrawerClose`
-
-function. This function is called when the drawer is closed.
-
-### `onDrawerOpen`
-
-function. This function is called when the drawer is opened.
-
-### `onDrawerSlide`
-
-function. This function is called as a drawer sliding open from touch events. The progress of the drawer opening/closing is passed back as 0 when closed and 1 when opened.
-
-### `onDrawerStateChanged`
-
-function. This function is called when the status of the drawer changes. It takes two arguments:
-
-- `newState: DrawerState` - state of the `Drawer`. It can be one of the following:
- - `Idle`
- - `Dragging`
- - `Settling`
-- `drawerWillShow: boolean` - if `true`, `Drawer` is about to open.
-
-### `enableTrackpadTwoFingerGesture` (iOS only)
-
-Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture.
-
-### `children`
-
-component or function. Children is a component which is rendered by default and is wrapped by drawer. However, it could be also a render function which takes an Animated value as a parameter that indicates the progress of drawer opening/closing animation (progress value is 0 when closed and 1 when opened) is the same way like `renderNavigationView` prop.
-
-### `mouseButton(value: MouseButton)` (Web & Android only)
-
-Allows users to choose which mouse button should handler respond to. The enum `MouseButton` consists of the following predefined fields:
-
-- `LEFT`
-- `RIGHT`
-- `MIDDLE`
-- `BUTTON_4`
-- `BUTTON_5`
-- `ALL`
-
-Arguments can be combined using `|` operator, e.g. `mouseButton(MouseButton.LEFT | MouseButton.RIGHT)`. Default value is set to `MouseButton.LEFT`.
-
-### `enableContextMenu(value: boolean)` (Web only)
-
-Specifies whether context menu should be enabled after clicking on underlying view with right mouse button. Default value is set to `false`.
-
-## Methods
-
-### `openDrawer(options)`
-
-`openDrawer` can take an optional `options` parameter which is an object, enabling further customization of the open animation.
-
-`options` has two optional properties:
-
-`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest).
-`speed`: number, controls speed of the animation. Default 12.
-
-### `closeDrawer(options)`
-
-`closeDrawer` can take an optional `options` parameter which is an object, enabling further customization of the close animation.
-
-`options` has two optional properties:
-
-`velocity`: number, the initial velocity of the object attached to the spring. Default 0 (object is at rest).
-`speed`: number, controls speed of the animation. Default 12.
-
-## Example:
-
-See the [drawer example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/basic/horizontalDrawer/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo).
-
-```js
-class Drawerable extends Component {
- handleDrawerSlide = (status) => {
- // outputs a value between 0 and 1
- console.log(status);
- };
-
- renderDrawer = () => {
- return (
-
- I am in the drawer!
-
- );
- };
-
- render() {
- return (
-
-
-
- Hello, it's me
-
-
-
- );
- }
-}
-```
diff --git a/docs/docs/components/swipeable.md b/docs/docs/components/swipeable.md
deleted file mode 100644
index da9bbc5593..0000000000
--- a/docs/docs/components/swipeable.md
+++ /dev/null
@@ -1,226 +0,0 @@
----
-id: swipeable
-title: Swipeable
-sidebar_label: Swipeable
----
-
-import useBaseUrl from '@docusaurus/useBaseUrl';
-import GifGallery from '@site/components/GifGallery'
-
-
-
-
-
-:::caution
-This component is deprecated.
-Please use [the reanimated version](/react-native-gesture-handler/docs/components/reanimated_swipeable).
-:::
-
-This component allows for implementing swipeable rows or similar interaction. It renders its children within a panable container allows for horizontal swiping left and right. While swiping one of two "action" containers can be shown depends on whether user swipes left or right (containers can be rendered by `renderLeftActions` or `renderRightActions` props).
-
-### Usage:
-
-Similarly to the `DrawerLayout`, `Swipeable` component isn't exported by default from the `react-native-gesture-handler` package. To use it, import it in the following way:
-
-```js
-import Swipeable from 'react-native-gesture-handler/Swipeable';
-```
-
-## Properties
-
-### `friction`
-
-A number that specifies how much the visual interaction will be delayed compared to the gesture distance. e.g. value of `1` will indicate that the swipeable panel should exactly follow the gesture, `2` means it is going to be two times "slower".
-
-### `leftThreshold`
-
-Distance from the left edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width.
-
-### `rightThreshold`
-
-Distance from the right edge at which released panel will animate to the open state (or the open panel will animate into the closed state). By default it's a half of the panel's width.
-
-### `dragOffsetFromLeftEdge`
-
-Distance that the panel must be dragged from the left edge to be considered a swipe. The default value is `10`.
-
-### `dragOffsetFromRightEdge`
-
-Distance that the panel must be dragged from the right edge to be considered a swipe. The default value is `10`.
-
-### `overshootLeft`
-
-A boolean value indicating if the swipeable panel can be pulled further than the left actions panel's width. It is set to `true` by default as long as the left panel render method is present.
-
-### `overshootRight`
-
-A boolean value indicating if the swipeable panel can be pulled further than the right actions panel's width. It is set to `true` by default as long as the right panel render method is present.
-
-### `overshootFriction`
-
-A number that specifies how much the visual interaction will be delayed compared to the gesture distance at overshoot. Default value is `1`, it mean no friction, for a native feel, try `8` or above.
-
-### `onSwipeableLeftOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)`
-:::
-
-Method that is called when left action panel gets open.
-
-### `onSwipeableRightOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableOpen(direction)`
-:::
-
-Method that is called when right action panel gets open.
-
-### `onSwipeableOpen`
-
-Method that is called when action panel gets open (either right or left). Takes swipe direction as
-an argument.
-
-### `onSwipeableClose`
-
-Method that is called when action panel is closed. Takes swipe direction as
-an argument.
-
-### `onSwipeableLeftWillOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)`
-:::
-
-Method that is called when left action panel starts animating on open.
-
-### `onSwipeableRightWillOpen`
-
-:::caution
-This callback is deprecated and will be removed in the next version. Please use `onSwipeableWillOpen(direction)`
-:::
-
-Method that is called when right action panel starts animating on open.
-
-### `onSwipeableWillOpen`
-
-Method that is called when action panel starts animating on open (either right or left). Takes swipe direction as
-an argument.
-
-### `onSwipeableWillClose`
-
-Method that is called when action panel starts animating on close. Takes swipe direction as
-an argument.
-
-### `renderLeftActions`
-
-Method that is expected to return an action panel that is going to be revealed from the left side when user swipes right.
-This map describes the values to use as inputRange for extra interpolation:
-AnimatedValue: [startValue, endValue]
-
-progressAnimatedValue: `[0, 1]`
-dragAnimatedValue: `[0, +]`
-
-To support `rtl` flexbox layouts use `flexDirection` styling.
-
-### `renderRightActions`
-
-Method that is expected to return an action panel that is going to be revealed from the right side when user swipes left.
-This map describes the values to use as inputRange for extra interpolation:
-AnimatedValue: [startValue, endValue]
-
-progressAnimatedValue: `[0, 1]`
-dragAnimatedValue: `[0, -]`
-
-To support `rtl` flexbox layouts use `flexDirection` styling.
-
-### `containerStyle`
-
-Style object for the container (Animated.View), for example to override `overflow: 'hidden'`.
-
-### `childrenContainerStyle`
-
-Style object for the children container (Animated.View), for example to apply `flex: 1`.
-
-### `enableTrackpadTwoFingerGesture` (iOS only)
-
-Enables two-finger gestures on supported devices, for example iPads with trackpads. If not enabled the gesture will require click + drag, with enableTrackpadTwoFingerGesture swiping with two fingers will also trigger the gesture.
-
-### `mouseButton(value: MouseButton)` (Web & Android only)
-
-Allows users to choose which mouse button should handler respond to. The enum `MouseButton` consists of the following predefined fields:
-
-- `LEFT`
-- `RIGHT`
-- `MIDDLE`
-- `BUTTON_4`
-- `BUTTON_5`
-- `ALL`
-
-Arguments can be combined using `|` operator, e.g. `mouseButton(MouseButton.LEFT | MouseButton.RIGHT)`. Default value is set to `MouseButton.LEFT`.
-
-### `enableContextMenu(value: boolean)` (Web only)
-
-Specifies whether context menu should be enabled after clicking on underlying view with right mouse button. Default value is set to `false`.
-
-## Methods
-
-Using reference to `Swipeable` it's possible to trigger some actions on it
-
-### `close`
-
-Method that closes component.
-
-### `openLeft`
-
-Method that opens component on left side.
-
-### `openRight`
-
-Method that opens component on right side.
-
-### `reset`
-
-Method that resets the swiping states of this `Swipeable` component.
-
-Unlike method `close`, this method does not trigger any animation.
-
-### Example:
-
-See the [swipeable example](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example/src/showcase/swipeable/index.tsx) from GestureHandler Example App or view it directly on your phone by visiting [our expo demo](https://snack.expo.io/@adamgrzybowski/react-native-gesture-handler-demo).
-
-```js
-import React, { Component } from 'react';
-import { Animated, StyleSheet, View } from 'react-native';
-import { RectButton } from 'react-native-gesture-handler';
-import Swipeable from 'react-native-gesture-handler/Swipeable';
-
-class AppleStyleSwipeableRow extends Component {
- renderLeftActions = (progress, dragX) => {
- const trans = dragX.interpolate({
- inputRange: [0, 50, 100, 101],
- outputRange: [-20, 0, 0, 1],
- });
- return (
-
-
- Archive
-
-
- );
- };
- render() {
- return (
-
- "hello"
-
- );
- }
-}
-```
diff --git a/docs/docs/fundamentals/installation.md b/docs/docs/fundamentals/installation.md
index 91b0763335..9416a2d078 100644
--- a/docs/docs/fundamentals/installation.md
+++ b/docs/docs/fundamentals/installation.md
@@ -193,20 +193,4 @@ import 'react-native-gesture-handler';
## Web
-There is no additional configuration required for the web, however, since the Gesture Handler 2.10.0 the new web implementation is enabled by default. It is recommended to check if the gestures in your app are working as expected since their behavior should now resemble the native platforms. If you don't want to use the new implementation, you can still revert back to the legacy one by enabling it at the beginning of your `index.js` file:
-
-```js
-import { enableLegacyWebImplementation } from 'react-native-gesture-handler';
-
-enableLegacyWebImplementation(true);
-```
-
-Nonetheless, it's recommended to adapt to the new implementation, as the legacy one will be dropped at some point in the future.
-
-If you want to start using the new implementation but don't want to upgrade Gesture Handler, you can enable it (starting with Gesture Handler 2.6.0) at the beginning of your `index.js` file:
-
-```js
-import { enableExperimentalWebImplementation } from 'react-native-gesture-handler';
-
-enableExperimentalWebImplementation(true);
-```
+There is no additional configuration required for the web.
diff --git a/e2e/web-tests/App.tsx b/e2e/web-tests/App.tsx
index cb95797300..5d32df2827 100644
--- a/e2e/web-tests/App.tsx
+++ b/e2e/web-tests/App.tsx
@@ -1,13 +1,10 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
-import { enableExperimentalWebImplementation } from 'react-native-gesture-handler';
import { DoubleTapTest } from './components/DoubleTapTest';
import { PanTest } from './components/PanTest';
import { TapTest } from './components/TapTest';
import { LongPressTest } from './components/LongPressTest';
-enableExperimentalWebImplementation();
-
export default function App() {
return (
diff --git a/example/App.tsx b/example/App.tsx
index 9e9dfb6957..de4e0ddcb1 100644
--- a/example/App.tsx
+++ b/example/App.tsx
@@ -29,7 +29,6 @@ import {
TouchablesIndex,
TouchableExample,
} from './src/release_tests/touchables';
-import Rows from './src/release_tests/rows';
import NestedFling from './src/release_tests/nestedFling';
import MouseButtons from './src/release_tests/mouseButtons';
import ContextMenu from './src/release_tests/contextMenu';
@@ -37,19 +36,16 @@ import NestedTouchables from './src/release_tests/nestedTouchables';
import NestedPressables from './src/release_tests/nestedPressables';
import NestedButtons from './src/release_tests/nestedButtons';
import PointerType from './src/release_tests/pointerType';
-import SwipeableReanimation from './src/release_tests/swipeableReanimation';
import NestedGestureHandlerRootViewWithModal from './src/release_tests/nestedGHRootViewWithModal';
import TwoFingerPan from './src/release_tests/twoFingerPan';
import { PinchableBox } from './src/recipes/scaleAndRotate';
import PanAndScroll from './src/recipes/panAndScroll';
import { BottomSheet } from './src/showcase/bottomSheet';
-import Swipeables from './src/showcase/swipeable';
import ChatHeads from './src/showcase/chatHeads';
import Draggable from './src/basic/draggable';
import MultiTap from './src/basic/multitap';
import BouncingBox from './src/basic/bouncing';
import PanResponder from './src/basic/panResponder';
-import HorizontalDrawer from './src/basic/horizontalDrawer';
import PagerAndDrawer from './src/basic/pagerAndDrawer';
import ForceTouch from './src/basic/forcetouch';
import Fling from './src/basic/fling';
@@ -64,7 +60,6 @@ import Calculator from './src/new_api/calculator';
import BottomSheetNewApi from './src/new_api/bottom_sheet';
import ChatHeadsNewApi from './src/new_api/chat_heads';
import DragNDrop from './src/new_api/drag_n_drop';
-import BetterHorizontalDrawer from './src/new_api/betterHorizontalDrawer';
import ManualGestures from './src/new_api/manualGestures/index';
import Hover from './src/new_api/hover';
import HoverableIcons from './src/new_api/hoverable_icons';
@@ -115,10 +110,6 @@ const EXAMPLES: ExamplesSection[] = [
{ name: 'Pressable', component: Pressable },
{ name: 'Hover', component: Hover },
{ name: 'Hoverable icons', component: HoverableIcons },
- {
- name: 'Horizontal Drawer (Reanimated 2 & RNGH 2)',
- component: BetterHorizontalDrawer,
- },
{
name: 'Manual gestures',
component: ManualGestures,
@@ -132,7 +123,6 @@ const EXAMPLES: ExamplesSection[] = [
{ name: 'Multitap', component: MultiTap },
{ name: 'Bouncing box', component: BouncingBox },
{ name: 'Pan responder', component: PanResponder },
- { name: 'Horizontal drawer', component: HorizontalDrawer },
{
name: 'Pager & drawer',
component: PagerAndDrawer,
@@ -157,7 +147,6 @@ const EXAMPLES: ExamplesSection[] = [
sectionTitle: 'Showcase',
data: [
{ name: 'Bottom sheet', component: BottomSheet },
- { name: 'Swipeables', component: Swipeables },
{ name: 'Chat heads', component: ChatHeads },
],
},
@@ -187,7 +176,6 @@ const EXAMPLES: ExamplesSection[] = [
},
{ name: 'Double pinch & rotate', component: DoublePinchRotate },
{ name: 'Double draggable', component: DoubleDraggable },
- { name: 'Rows', component: Rows },
{ name: 'Nested Fling', component: NestedFling },
{
name: 'Combo',
@@ -203,7 +191,6 @@ const EXAMPLES: ExamplesSection[] = [
},
{ name: 'PointerType', component: PointerType },
{ name: 'Reanimated Drawer Layout', component: ReanimatedDrawerLayout },
- { name: 'Swipeable Reanimation', component: SwipeableReanimation },
{ name: 'RectButton (borders)', component: RectButtonBorders },
{ name: 'Gesturized pressable', component: GesturizedPressable },
{
diff --git a/example/src/basic/horizontalDrawer/index.tsx b/example/src/basic/horizontalDrawer/index.tsx
deleted file mode 100644
index a99ba85ba2..0000000000
--- a/example/src/basic/horizontalDrawer/index.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-import React, { Component } from 'react';
-import {
- Platform,
- StyleSheet,
- Text,
- Animated,
- View,
- TextInput,
-} from 'react-native';
-
-import { RectButton } from 'react-native-gesture-handler';
-
-import { DrawerLayout, DrawerType } from 'react-native-gesture-handler';
-
-const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide'];
-const PARALLAX = [false, false, true, false];
-
-type PageProps = {
- fromLeft: boolean;
- type: DrawerType;
- parallaxOn: boolean;
- flipSide: () => void;
- nextType: () => void;
- openDrawer: () => void;
-};
-
-const Page = ({
- fromLeft,
- type,
- parallaxOn,
- flipSide,
- nextType,
- openDrawer,
-}: PageProps) => (
-
- Hi 👋
-
-
- Drawer to the {fromLeft ? 'left' : 'right'}! {'->'} Flip
-
-
-
-
- Type {type} {parallaxOn && 'with parallax!'} -> Next
-
-
-
- Open drawer
-
-
-
-);
-
-export default class Example extends Component<
- Record,
- { fromLeft: boolean; type: number }
-> {
- state = { fromLeft: true, type: 0 };
-
- private renderParallaxDrawer = (progressValue: Animated.Value) => {
- const parallax = progressValue.interpolate({
- inputRange: [0, 1],
- outputRange: [this.state.fromLeft ? -50 : 50, 0],
- });
- const animatedStyles = {
- transform: [{ translateX: parallax }],
- };
- return (
-
- I am in the drawer!
-
- Watch parallax animation while you pull the drawer!
-
-
- );
- };
-
- private renderDrawer = () => {
- return (
-
- I am in the drawer!
-
- );
- };
- private drawer?: DrawerLayout | null;
-
- render() {
- const drawerType: DrawerType = TYPES[this.state.type];
- const parallax = PARALLAX[this.state.type];
- return (
-
- {
- this.drawer = drawer;
- }}
- enableTrackpadTwoFingerGesture
- drawerWidth={200}
- keyboardDismissMode="on-drag"
- drawerPosition={this.state.fromLeft ? 'left' : 'right'}
- drawerType={drawerType}
- drawerBackgroundColor="#ddd"
- overlayColor={drawerType === 'front' ? 'black' : '#00000000'}
- renderNavigationView={
- parallax ? this.renderParallaxDrawer : this.renderDrawer
- }
- contentContainerStyle={
- // careful; don't elevate the child container
- // over top of the drawer when the drawer is supposed
- // to be in front - you won't be able to see/open it.
- drawerType === 'front'
- ? {}
- : Platform.select({
- ios: {
- shadowColor: '#000',
- shadowOpacity: 0.5,
- shadowOffset: { width: 0, height: 2 },
- shadowRadius: 60,
- },
- android: {
- elevation: 100,
- backgroundColor: '#000',
- },
- })
- }>
-
- this.setState((prevState) => ({
- fromLeft: !prevState.fromLeft,
- }))
- }
- nextType={() =>
- this.setState((prevState) => ({
- type: (prevState.type + 1) % TYPES.length,
- }))
- }
- openDrawer={() => this.drawer?.openDrawer({ speed: 14 })}
- />
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- page: {
- ...StyleSheet.absoluteFillObject,
- alignItems: 'center',
- paddingTop: 40,
- backgroundColor: 'gray',
- },
- pageText: {
- fontSize: 21,
- color: 'white',
- },
- rectButton: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: 'white',
- },
- rectButtonText: {
- backgroundColor: 'transparent',
- },
- drawerContainer: {
- flex: 1,
- paddingTop: 10,
- },
- pageInput: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: '#eee',
- },
- drawerText: {
- margin: 10,
- fontSize: 15,
- textAlign: 'left',
- },
-});
diff --git a/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx b/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx
deleted file mode 100644
index 950505b7d8..0000000000
--- a/example/src/new_api/betterHorizontalDrawer/BetterHorizonatalDrawer.tsx
+++ /dev/null
@@ -1,627 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import {
- I18nManager,
- LayoutChangeEvent,
- StatusBarAnimation,
- StyleProp,
- StyleSheet,
- ViewStyle,
- Keyboard,
- StatusBar,
-} from 'react-native';
-import {
- DrawerKeyboardDismissMode,
- DrawerLockMode,
- DrawerPosition,
- DrawerType,
- GestureDetector,
- Gesture,
-} from 'react-native-gesture-handler';
-import Animated, {
- runOnJS,
- useAnimatedStyle,
- useDerivedValue,
- useSharedValue,
- withSpring,
-} from 'react-native-reanimated';
-
-export enum BetterDrawerState {
- IDLE = 'Idle',
- DRAGGING = 'Dragging',
- SETTLING = 'Settling',
-}
-
-export interface BetterDrawerLayoutProps {
- /**
- * This attribute is present in the standard implementation already and is one
- * of the required params. Gesture handler version of DrawerLayout make it
- * possible for the function passed as `renderNavigationView` to take an
- * Animated value as a parameter that indicates the progress of drawer
- * opening/closing animation (progress value is 0 when closed and 1 when
- * opened). This can be used by the drawer component to animated its children
- * while the drawer is opening or closing.
- */
- renderNavigationView: (
- progressAnimatedValue: Animated.SharedValue
- ) => React.ReactNode;
-
- drawerPosition?: DrawerPosition;
-
- drawerWidth?: number;
-
- drawerBackgroundColor?: string;
-
- drawerLockMode?: DrawerLockMode;
-
- keyboardDismissMode?: DrawerKeyboardDismissMode;
-
- /**
- * Called when the drawer is closed.
- */
- onDrawerClose?: () => void;
-
- /**
- * Called when the drawer is opened.
- */
- onDrawerOpen?: () => void;
-
- /**
- * Called when the status of the drawer changes.
- */
- onDrawerStateChanged?: (
- newState: BetterDrawerState,
- drawerWillShow: boolean
- ) => void;
-
- drawerType?: DrawerType;
-
- /**
- * Defines how far from the edge of the content view the gesture should
- * activate.
- */
- edgeWidth?: number;
-
- minSwipeDistance?: number;
-
- /**
- * When set to true Drawer component will use
- * {@link https://reactnative.dev/docs/statusbar StatusBar} API to hide the OS
- * status bar whenever the drawer is pulled or when its in an "open" state.
- */
- hideStatusBar?: boolean;
-
- /**
- * @default 'slide'
- *
- * Can be used when hideStatusBar is set to true and will select the animation
- * used for hiding/showing the status bar. See
- * {@link https://reactnative.dev/docs/statusbar StatusBar} documentation for
- * more details
- */
- statusBarAnimation?: StatusBarAnimation;
-
- /**
- * @default black
- *
- * Color of a semi-transparent overlay to be displayed on top of the content
- * view when drawer gets open. A solid color should be used as the opacity is
- * added by the Drawer itself and the opacity of the overlay is animated (from
- * 0% to 70%).
- */
- overlayColor?: string;
-
- contentContainerStyle?: StyleProp;
-
- drawerContainerStyle?: StyleProp;
-
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- /**
- * Called when the pan gesture gets updated, position represents a fraction of
- * the drawer that is visible
- */
- onDrawerSlide?: (position: number) => void;
-
- children?: React.ReactNode;
-}
-
-interface OverlayProps {
- drawerType: DrawerType;
- color: string;
- progress: Animated.SharedValue;
- lockMode: DrawerLockMode;
- close: () => void;
-}
-
-function Overlay(props: OverlayProps) {
- const overlayStyle = useAnimatedStyle(() => ({
- backgroundColor: props.color,
- opacity: props.progress.value,
- transform: [
- {
- translateX:
- // when the overlay should not be visible move it off the screen
- // to prevent it from intercepting touch events on Android
- props.drawerType !== 'front' || props.progress.value === 0
- ? 10000
- : 0,
- },
- ],
- }));
-
- const tap = Gesture.Tap();
- tap.onEnd((_event, success) => {
- 'worklet';
- if (success && props.lockMode !== 'locked-open') {
- // close the drawer when tapped on the overlay only if the gesture
- // was not cancelled and it's not locked in opened state
- props.close();
- }
- });
-
- return (
-
-
-
- );
-}
-
-export interface DrawerLayoutController {
- open: () => void;
- close: () => void;
-}
-
-export const DrawerLayout = React.forwardRef<
- DrawerLayoutController,
- BetterDrawerLayoutProps
->(
- (
- {
- drawerWidth = 200,
- drawerPosition = 'left',
- drawerType = 'front',
- edgeWidth = 20,
- minSwipeDistance = 3,
- overlayColor = 'rgba(0, 0, 0, 0.7)',
- drawerLockMode = 'unlocked',
- enableTrackpadTwoFingerGesture = false,
- keyboardDismissMode,
- statusBarAnimation,
- hideStatusBar,
- drawerBackgroundColor,
- drawerContainerStyle,
- contentContainerStyle,
- children,
- renderNavigationView,
- onDrawerClose,
- onDrawerOpen,
- onDrawerSlide,
- onDrawerStateChanged,
- }: BetterDrawerLayoutProps,
- ref
- ) => {
- const animationConfig = { damping: 30, stiffness: 250 };
-
- const fromLeft = drawerPosition === 'left';
- const drawerSlide = drawerType !== 'back';
- const containerSlide = drawerType !== 'front';
-
- // setting NaN as a starting value allows to tell when the value gets changes
- // for the first time
- const [containerWidth, setContainerWidth] = useState(Number.NaN);
- const [drawerVisible, setDrawerVisible] = useState(false);
-
- const drawerState = useSharedValue(BetterDrawerState.IDLE);
- // between 0 and drawerWidth (drawer on the left) or -drawerWidth and 0 (drawer on the right)
- const drawerOffset = useSharedValue(0);
- // stores value of the offset at the start of the gesture
- const drawerSavedOffset = useSharedValue(0);
- // stores the translation that is supposed to be ignored (user tried to
- // drag while animation was running)
- const ignoredOffset = useSharedValue(0);
- // stores the x coordinate of the drag starting point (to ignore dragging on the overlay)
- const dragStartPosition = useSharedValue(0);
- // between 0 and 1, 0 - closed, 1 - opened
- const openingProgress = useDerivedValue(() => {
- if (fromLeft) {
- return drawerOffset.value / drawerWidth;
- } else {
- return -drawerOffset.value / drawerWidth;
- }
- }, [drawerOffset, containerWidth, drawerWidth, fromLeft]);
-
- // we rely on row and row-reverse flex directions to position the drawer
- // properly. Apparently for RTL these are flipped which requires us to use
- // the opposite setting for the drawer to appear from left or right
- // according to the drawerPosition prop
- const reverseContentDirection = I18nManager.isRTL ? fromLeft : !fromLeft;
-
- // set the drawer to closed position when the props change to prevent it from
- // opening or moving on the screen
- useEffect(() => {
- drawerOffset.value = 0;
- drawerSavedOffset.value = 0;
-
- setDrawerVisible(false);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [drawerWidth, drawerPosition, drawerType]);
-
- // measure the container
- function handleContainerLayout({ nativeEvent }: LayoutChangeEvent) {
- setContainerWidth(nativeEvent.layout.width);
- }
-
- function onDragStart() {
- if (keyboardDismissMode === 'on-drag') {
- Keyboard.dismiss();
- }
-
- // this is required in addition to the similar call below, because the gesture
- // doesn't change `drawerVisible` state to prevent re-render during gesture
- // so when dragging from closed it wouldn't hide the status bar
- if (hideStatusBar) {
- StatusBar.setHidden(true, statusBarAnimation ?? 'slide');
- }
- }
-
- function setState(newState: BetterDrawerState, willShow: boolean) {
- if (hideStatusBar) {
- StatusBar.setHidden(willShow, statusBarAnimation ?? 'slide');
- }
-
- // dispach events
- if (drawerState.value !== newState || drawerVisible !== willShow) {
- // send state change event only when the state changed or the visibility of the
- // drawer (for example when drawer is in SETTLING state after opening and the user
- // taps on the overlay the state is still settling, but willShow is now false)
- onDrawerStateChanged?.(newState, willShow);
- }
-
- if (drawerVisible !== willShow) {
- setDrawerVisible(willShow);
- }
-
- if (newState === BetterDrawerState.IDLE) {
- if (willShow) {
- onDrawerOpen?.();
- } else {
- onDrawerClose?.();
- }
- }
-
- drawerState.value = newState;
- }
-
- function open() {
- 'worklet';
- if (fromLeft && drawerOffset.value < drawerWidth) {
- // drawer is on the left and is not fully opened
- runOnJS(setState)(BetterDrawerState.SETTLING, true);
-
- drawerOffset.value = withSpring(
- drawerWidth,
- animationConfig,
- (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
- );
- } else if (!fromLeft && drawerOffset.value > -drawerWidth) {
- // drawer is on the right and is not fully opened
- runOnJS(setState)(BetterDrawerState.SETTLING, true);
-
- drawerOffset.value = withSpring(
- -drawerWidth,
- animationConfig,
- (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
- );
- } else {
- // drawer is fully opened
- runOnJS(setState)(BetterDrawerState.IDLE, true);
- }
- }
-
- function close() {
- 'worklet';
- if (fromLeft && drawerOffset.value > 0) {
- // drawer is on the left and is not fully closed
- runOnJS(setState)(BetterDrawerState.SETTLING, false);
-
- drawerOffset.value = withSpring(0, animationConfig, (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- });
- } else if (!fromLeft && drawerOffset.value < 0) {
- // drawer is on the right and is not fully closed
- runOnJS(setState)(BetterDrawerState.SETTLING, false);
-
- drawerOffset.value = withSpring(0, animationConfig, (finished) => {
- drawerSavedOffset.value = drawerOffset.value;
- if (finished) {
- // animation cannot be interrupted by a drag, but can be by
- // calling close or open (through tap or a controller)
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- });
- } else {
- // drawer is fully closed
- runOnJS(setState)(BetterDrawerState.IDLE, false);
- }
- }
-
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation = (fromLeft ? 1 : -1) * (drawerVisible ? -1 : 1);
-
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: drawerVisible ? undefined : edgeWidth }
- : { right: 0, width: drawerVisible ? undefined : edgeWidth };
-
- // *** THIS IS THE LARGE COMMENT ABOVE ***
- //
- // While closing the drawer when user starts gesture outside of its area (in greyed
- // out part of the window), we want the drawer to follow only once finger reaches the
- // edge of the drawer.
- // E.g. on the diagram below drawer is illustrate by X signs and the greyed out area by
- // dots. The touch gesture starts at '*' and moves left, touch path is indicated by
- // an arrow pointing left
- // 1) +---------------+ 2) +---------------+ 3) +---------------+ 4) +---------------+
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|.<-*..| |XXXXXXXX|<--*..| |XXXXX|<-----*..|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // +---------------+ +---------------+ +---------------+ +---------------+
- //
- // For the above to work properly we define animated value that will keep
- // start position of the gesture. Then we use that value to calculate how
- // much we need to subtract from the dragX. If the gesture started on the
- // greyed out area we take the distance from the edge of the drawer to the
- // start position. Otherwise we don't subtract at all and the drawer be
- // pulled back as soon as you start the pan.
- //
- // This is used only when drawerType is "front"
- //
-
- const pan = Gesture.Pan();
- pan.failOffsetY([-15, 15]);
- pan.hitSlop(hitSlop);
- pan.activeOffsetX(gestureOrientation * minSwipeDistance);
- pan.enableTrackpadTwoFingerGesture(enableTrackpadTwoFingerGesture);
- pan.enabled(
- drawerLockMode !== 'locked-closed' && drawerLockMode !== 'locked-open'
- );
- pan.onStart((event) => {
- 'worklet';
- ignoredOffset.value = 0;
- dragStartPosition.value = event.x;
- });
- pan.onUpdate((event) => {
- 'worklet';
- if (drawerState.value === BetterDrawerState.IDLE) {
- runOnJS(setState)(BetterDrawerState.DRAGGING, drawerVisible);
- runOnJS(onDragStart)();
- }
-
- if (drawerState.value === BetterDrawerState.DRAGGING) {
- let newOffset =
- drawerSavedOffset.value + event.translationX - ignoredOffset.value;
-
- if (fromLeft) {
- // refer to the large comment above
- if (
- drawerType === 'front' &&
- event.translationX < 0 &&
- drawerOffset.value > 0
- ) {
- newOffset += dragStartPosition.value - drawerWidth;
- }
-
- // clamp the offset so the drawer does not move away from the edge
- newOffset = Math.max(0, Math.min(drawerWidth, newOffset));
- } else {
- // refer to the large comment above
- if (
- drawerType === 'front' &&
- event.translationX > 0 &&
- drawerOffset.value < 0
- ) {
- newOffset +=
- dragStartPosition.value - (containerWidth - drawerWidth);
- }
-
- // clamp the offset so the drawer does not move away from the edge
- newOffset = Math.max(-drawerWidth, Math.min(0, newOffset));
- }
-
- drawerOffset.value = newOffset;
-
- // send event if there is a listener
- if (onDrawerSlide !== undefined) {
- runOnJS(onDrawerSlide)(openingProgress.value);
- }
- } else {
- // drawerState is SETTLING, save the translation to ignore it later
- ignoredOffset.value = event.translationX;
- }
- });
- pan.onEnd((_event) => {
- 'worklet';
- if (drawerState.value === BetterDrawerState.DRAGGING) {
- // update offsets and animations only when the drag was not ignored
- drawerSavedOffset.value = drawerOffset.value;
-
- // if the drawer was dragged more than half of its width open it,
- // otherwise close it
- if (fromLeft) {
- if (drawerOffset.value > drawerWidth / 2) {
- open();
- } else {
- close();
- }
- } else {
- if (drawerOffset.value < -drawerWidth / 2) {
- open();
- } else {
- close();
- }
- }
- }
- });
-
- const dynamicDrawerStyles = {
- backgroundColor: drawerBackgroundColor,
- width: drawerWidth,
- };
-
- const drawerStyle = useAnimatedStyle(() => {
- let translateX = 0;
-
- if (drawerSlide) {
- // drawer is supposed to be moved with the gesture (in this case
- // drawer is anchored to be off the screen when not opened)
- if (fromLeft) {
- translateX = -drawerWidth;
- } else {
- translateX = containerWidth;
- }
- translateX += drawerOffset.value;
- } else {
- // drawer is stationary (in this case drawer is below the content
- // so it's anchored left edge to left edge or right to right)
- if (fromLeft) {
- translateX = 0;
- } else {
- translateX = containerWidth - drawerWidth;
- }
- }
-
- // if the drawer is not visible move it off the screen to prevent it
- // from intercepting touch events on Android
- if (drawerOffset.value === 0) {
- translateX = 10000;
- }
-
- return {
- flexDirection: reverseContentDirection ? 'row-reverse' : 'row',
- transform: [{ translateX }],
- };
- });
-
- const containerStyle = useAnimatedStyle(() => {
- let translateX = 0;
-
- if (containerSlide) {
- // the container should be moved with the gesture
- translateX = drawerOffset.value;
- }
-
- return {
- transform: [{ translateX }],
- };
- });
-
- if (ref !== null) {
- // ref is set, create a controller and pass it
- const controller: DrawerLayoutController = {
- open: () => {
- open();
- },
- close: () => {
- close();
- },
- };
-
- if (typeof ref === 'function') {
- ref(controller);
- } else {
- ref.current = controller;
- }
- }
-
- return (
-
-
-
- {children}
-
-
-
-
- {renderNavigationView(openingProgress)}
-
-
-
- );
- }
-);
-
-const styles = StyleSheet.create({
- drawerContainer: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1001,
- flexDirection: 'row',
- },
- containerInFront: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1002,
- },
- containerOnBack: {
- ...StyleSheet.absoluteFillObject,
- },
- main: {
- flex: 1,
- zIndex: 0,
- overflow: 'hidden',
- },
- overlay: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1000,
- },
-});
diff --git a/example/src/new_api/betterHorizontalDrawer/index.tsx b/example/src/new_api/betterHorizontalDrawer/index.tsx
deleted file mode 100644
index c2f7008a8e..0000000000
--- a/example/src/new_api/betterHorizontalDrawer/index.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import React, { useRef, useState } from 'react';
-
-import { StyleSheet, Text, View, TextInput } from 'react-native';
-
-import { DrawerType, RectButton } from 'react-native-gesture-handler';
-import {
- DrawerLayoutController,
- DrawerLayout,
-} from './BetterHorizonatalDrawer';
-import Animated, {
- useAnimatedStyle,
- interpolate,
-} from 'react-native-reanimated';
-
-const TYPES: DrawerType[] = ['front', 'back', 'back', 'slide'];
-const PARALLAX = [false, false, true, false];
-
-interface PageProps {
- fromLeft: boolean;
- type: DrawerType;
- parallaxOn: boolean;
- flipSide: () => void;
- nextType: () => void;
- openDrawer: () => void;
-}
-
-function Page({
- fromLeft,
- type,
- parallaxOn,
- flipSide,
- nextType,
- openDrawer,
-}: PageProps) {
- return (
-
- Hi 👋
-
-
- Drawer to the {fromLeft ? 'left' : 'right'}! {'->'} Flip
-
-
-
-
- Type {type} {parallaxOn && 'with parallax!'} -> Next
-
-
-
- Open drawer
-
-
-
- );
-}
-
-function DrawerContent(
- offset: Animated.SharedValue,
- parallax: boolean,
- fromLeft: boolean
-) {
- const animatedStyles = useAnimatedStyle(() => ({
- transform: [
- {
- translateX: parallax
- ? interpolate(offset.value, [0, 1], [fromLeft ? -50 : 50, 0])
- : 0,
- },
- ],
- }));
-
- return (
-
-
- {parallax ? 'Drawer with parallax' : 'Drawer'}
-
-
- );
-}
-
-export default function Example() {
- const [onLeft, setOnLeft] = useState(true);
- const [type, setType] = useState(0);
- const controller = useRef(null);
-
- return (
-
- {
- return DrawerContent(offset, PARALLAX[type], onLeft);
- }}
- keyboardDismissMode="on-drag"
- drawerBackgroundColor="white"
- ref={controller}>
- {
- setOnLeft(!onLeft);
- }}
- type={TYPES[type]}
- nextType={() => {
- setType((type + 1) % TYPES.length);
- }}
- parallaxOn={PARALLAX[type]}
- openDrawer={() => {
- controller.current?.open();
- }}
- />
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- page: {
- ...StyleSheet.absoluteFillObject,
- alignItems: 'center',
- paddingTop: 40,
- backgroundColor: 'gray',
- },
- pageText: {
- fontSize: 21,
- color: 'white',
- },
- rectButton: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: 'white',
- },
- rectButtonText: {
- backgroundColor: 'transparent',
- },
- drawerContainer: {
- flex: 1,
- paddingTop: 10,
- },
- pageInput: {
- height: 60,
- padding: 10,
- alignSelf: 'stretch',
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: 20,
- backgroundColor: '#eee',
- },
- drawerText: {
- margin: 10,
- fontSize: 15,
- textAlign: 'left',
- },
-});
diff --git a/example/src/new_api/swipeable/index.tsx b/example/src/new_api/swipeable/index.tsx
index f595afad8d..85138234fe 100644
--- a/example/src/new_api/swipeable/index.tsx
+++ b/example/src/new_api/swipeable/index.tsx
@@ -1,11 +1,20 @@
-import React from 'react';
+import React, { useRef } from 'react';
import { StyleSheet, Text, View, I18nManager } from 'react-native';
-import { FlatList, RectButton } from 'react-native-gesture-handler';
+import { FlatList, Pressable, RectButton } from 'react-native-gesture-handler';
+
+import Reanimated, {
+ SharedValue,
+ useAnimatedStyle,
+} from 'react-native-reanimated';
import AppleStyleSwipeableRow from './AppleStyleSwipeableRow';
import GmailStyleSwipeableRow from './GmailStyleSwipeableRow';
+import ReanimatedSwipeable, {
+ SwipeableMethods,
+} from 'react-native-gesture-handler/ReanimatedSwipeable';
+
// To toggle LTR/RTL change to `true`
I18nManager.allowRTL(false);
@@ -42,25 +51,111 @@ const SwipeableRow = ({ item, index }: { item: DataRow; index: number }) => {
}
};
+function LeftAction(prog: SharedValue, drag: SharedValue) {
+ const styleAnimation = useAnimatedStyle(() => {
+ console.log('[R] showLeftProgress:', prog.value);
+ console.log('[R] appliedTranslation:', drag.value);
+
+ return {
+ transform: [{ translateX: drag.value - 60 }],
+ };
+ });
+
+ return (
+
+ Text
+
+ );
+}
+
+function RightAction(prog: SharedValue, drag: SharedValue) {
+ const styleAnimation = useAnimatedStyle(() => {
+ console.log('[R] showRightProgress:', prog.value);
+ console.log('[R] appliedTranslation:', drag.value);
+
+ return {
+ transform: [{ translateX: drag.value + 60 }],
+ };
+ });
+
+ return (
+
+ Text
+
+ );
+}
+
const Separator = () => ;
export default function App() {
+ const reanimatedRef = useRef(null);
return (
- (
-
- )}
- keyExtractor={(_item, index) => `message ${index}`}
- />
+
+
+
+
+ Programatical controls
+
+ {
+ reanimatedRef.current!.openLeft();
+ }}>
+ open left
+
+ {
+ reanimatedRef.current!.close();
+ }}>
+ close
+
+ {
+ reanimatedRef.current!.reset();
+ }}>
+ reset
+
+ {
+ reanimatedRef.current!.openRight();
+ }}>
+ open right
+
+
+
+
+
+
+
+ Use the programatic control panel
+
+
+
+ (
+
+ )}
+ keyExtractor={(_item, index) => `message ${index}`}
+ />
+
);
}
const styles = StyleSheet.create({
rectButton: {
- flex: 1,
- height: 80,
paddingVertical: 10,
paddingHorizontal: 20,
justifyContent: 'space-between',
@@ -87,6 +182,31 @@ const styles = StyleSheet.create({
color: '#999',
fontWeight: 'bold',
},
+ leftAction: { width: 60, height: 60, backgroundColor: '#ff5ca3' },
+ rightAction: { width: 60, height: 60, backgroundColor: '#b658b6' },
+ swipeable: {
+ height: 60,
+ backgroundColor: 'white',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ controlPanelWrapper: {
+ backgroundColor: 'white',
+ alignItems: 'center',
+ },
+ controlPanel: {
+ backgroundColor: 'white',
+ alignItems: 'center',
+ flexDirection: 'row',
+ },
+ control: {
+ flex: 1,
+ height: 40,
+ borderWidth: StyleSheet.hairlineWidth,
+ borderColor: 'rgb(200, 199, 204)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
});
const DATA: DataRow[] = [
diff --git a/example/src/release_tests/combo/InfoButton.tsx b/example/src/release_tests/combo/InfoButton.tsx
new file mode 100644
index 0000000000..353c372847
--- /dev/null
+++ b/example/src/release_tests/combo/InfoButton.tsx
@@ -0,0 +1,39 @@
+import React, { View, Text, StyleSheet } from 'react-native';
+import {
+ BorderlessButton,
+ BorderlessButtonProps,
+} from 'react-native-gesture-handler';
+
+export const InfoButton = (props: BorderlessButtonProps & { name: string }) => (
+ window.alert(`${props.name} info button clicked`)}>
+
+ i
+
+
+);
+
+const styles = StyleSheet.create({
+ infoButton: {
+ width: 40,
+ height: 40,
+ },
+ infoButtonBorders: {
+ borderColor: '#467AFB',
+ borderWidth: 2,
+ width: 20,
+ height: 20,
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderRadius: 10,
+ margin: 10,
+ },
+ infoButtonText: {
+ color: '#467AFB',
+ fontWeight: 'bold',
+ backgroundColor: 'transparent',
+ },
+});
diff --git a/example/src/release_tests/combo/index.tsx b/example/src/release_tests/combo/index.tsx
index 30ac11b9d0..f327956be9 100644
--- a/example/src/release_tests/combo/index.tsx
+++ b/example/src/release_tests/combo/index.tsx
@@ -21,12 +21,14 @@ import {
} from 'react-native-gesture-handler';
import Slider from '@react-native-community/slider';
-import { Swipeable, InfoButton } from '../rows';
+import Swipeable from 'react-native-gesture-handler/ReanimatedSwipeable';
+
import { DraggableBox } from '../../basic/draggable';
import { PinchableBox } from '../../recipes/scaleAndRotate';
import { PressBox } from '../../basic/multitap';
import { LoremIpsum } from '../../common';
+import { InfoButton } from './InfoButton';
const CHILD_REF = 'CHILD_REF';
diff --git a/example/src/release_tests/rows/index.tsx b/example/src/release_tests/rows/index.tsx
deleted file mode 100644
index 02eae1ed6e..0000000000
--- a/example/src/release_tests/rows/index.tsx
+++ /dev/null
@@ -1,283 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import {
- Animated,
- StyleSheet,
- Text,
- View,
- LayoutChangeEvent,
-} from 'react-native';
-
-import {
- PanGestureHandler,
- ScrollView,
- State,
- RectButton,
- LongPressGestureHandler,
- PanGestureHandlerGestureEvent,
- PanGestureHandlerStateChangeEvent,
- BorderlessButton,
- BorderlessButtonProps,
-} from 'react-native-gesture-handler';
-
-import { USE_NATIVE_DRIVER } from '../../config';
-import { LoremIpsum } from '../../common';
-
-const RATIO = 3;
-
-type Props = {
- enableTrackpadTwoFingerGesture: boolean;
-};
-
-export class Swipeable extends Component> {
- private width: number;
- private dragX: Animated.Value;
- private transX: Animated.AnimatedInterpolation;
- private showLeftAction: Animated.AnimatedInterpolation;
- private showRightAction: Animated.AnimatedInterpolation;
- private onGestureEvent: (event: PanGestureHandlerGestureEvent) => void;
- constructor(props: Props) {
- super(props);
- this.width = 0;
- this.dragX = new Animated.Value(0);
- this.transX = this.dragX.interpolate({
- inputRange: [0, RATIO],
- outputRange: [0, 1],
- });
- this.showLeftAction = this.dragX.interpolate({
- inputRange: [-1, 0, 1],
- outputRange: [0, 0, 1],
- });
- this.showRightAction = this.dragX.interpolate({
- inputRange: [-1, 0, 1],
- outputRange: [1, 0, 0],
- });
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: this.dragX } }],
- { useNativeDriver: USE_NATIVE_DRIVER }
- );
- }
- private onHandlerStateChange = (event: PanGestureHandlerStateChangeEvent) => {
- if (event.nativeEvent.oldState === State.ACTIVE) {
- const dragToss = 0.05;
- const endOffsetX =
- event.nativeEvent.translationX + dragToss * event.nativeEvent.velocityX;
-
- let toValue = 0;
- if (endOffsetX > this.width / 2) {
- toValue = this.width * RATIO;
- } else if (endOffsetX < -this.width / 2) {
- toValue = -this.width * RATIO;
- }
-
- Animated.spring(this.dragX, {
- velocity: event.nativeEvent.velocityX,
- tension: 15,
- friction: 5,
- toValue,
- useNativeDriver: USE_NATIVE_DRIVER,
- }).start();
- }
- };
- private onLayout = (event: LayoutChangeEvent) => {
- this.width = event.nativeEvent.layout.width;
- };
- private reset = () => {
- Animated.spring(this.dragX, {
- toValue: 0,
- useNativeDriver: USE_NATIVE_DRIVER,
- tension: 15,
- friction: 5,
- }).start();
- };
- render() {
- const { children } = this.props;
- return (
-
-
-
- Green
-
-
-
-
- Red
-
-
-
-
- {children}
-
-
-
- );
- }
-}
-
-export const InfoButton = (props: BorderlessButtonProps & { name: string }) => (
- window.alert(`${props.name} info button clicked`)}>
-
- i
-
-
-);
-
-export default class Example extends Component {
- render() {
- return (
-
-
-
-
- window.alert('First row clicked')}>
-
- Swipe this row & observe highlight delay
-
- {/* Info icon will cancel when you scroll in the direction of the scrollview
- but if you move finger horizontally it would allow you to "re-enter" into
- an active state. This is typical for most of the buttons on iOS (but not
- on Android where the touch cancels as soon as you leave the area of the
- button). */}
-
-
-
-
- window.alert('Second row clicked')}>
-
- Second info icon will block scrolling
-
- {/* Info icon will block interaction with other gesture handlers including
- the scrollview handler its a descendant of. This is typical for buttons
- embedded in a scrollable content on iOS. */}
-
-
-
- window.alert('Third row clicked')}>
-
- This one will cancel when you drag outside
-
- {/* Info icon will cancel when you drag your finger outside of its bounds and
- then back unlike all the previous icons that would activate when you re-enter
- their activation area. This is a typical bahaviour for android but less frequent
- for most of the iOS native apps. */}
-
-
-
-
- window.alert('Fourth row clicked')}>
-
- This row is "disabled" but you can swipe it
-
-
-
-
-
- // eslint-disable-next-line no-alert
- nativeEvent.state === State.ACTIVE && window.alert('Long')
- }>
- window.alert('Fifth row clicked')}>
-
- Clickable row with long press handler
-
-
-
-
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- rectButton: {
- flex: 1,
- height: 60,
- padding: 10,
- justifyContent: 'space-between',
- alignItems: 'center',
- flexDirection: 'row',
- backgroundColor: 'white',
- },
- rowAction: {
- ...StyleSheet.absoluteFillObject,
- justifyContent: 'center',
- alignItems: 'center',
- },
- leftAction: {
- backgroundColor: '#4CAF50',
- },
- rightAction: {
- backgroundColor: '#F44336',
- },
- actionButtonText: {
- color: 'white',
- fontSize: 16,
- },
- buttonDelimiter: {
- height: 1,
- backgroundColor: '#999',
- },
- buttonText: {
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
- infoButton: {
- width: 40,
- height: 40,
- },
- infoButtonBorders: {
- borderColor: '#467AFB',
- borderWidth: 2,
- width: 20,
- height: 20,
- alignItems: 'center',
- justifyContent: 'center',
- borderRadius: 10,
- margin: 10,
- },
- infoButtonText: {
- color: '#467AFB',
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
-});
diff --git a/example/src/release_tests/swipeableReanimation/index.tsx b/example/src/release_tests/swipeableReanimation/index.tsx
deleted file mode 100644
index 25d49536c8..0000000000
--- a/example/src/release_tests/swipeableReanimation/index.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-import React, { useRef } from 'react';
-import { Text, Animated, StyleSheet, View } from 'react-native';
-
-import {
- Swipeable,
- GestureHandlerRootView,
- Pressable,
-} from 'react-native-gesture-handler';
-import ReanimatedSwipeable, {
- SwipeableMethods,
-} from 'react-native-gesture-handler/ReanimatedSwipeable';
-import Reanimated, {
- SharedValue,
- useAnimatedStyle,
-} from 'react-native-reanimated';
-
-function LeftAction(prog: SharedValue, drag: SharedValue) {
- const styleAnimation = useAnimatedStyle(() => {
- console.log('[R] showLeftProgress:', prog.value);
- console.log('[R] appliedTranslation:', drag.value);
-
- return {
- transform: [{ translateX: drag.value - 50 }],
- };
- });
-
- return (
-
- Text
-
- );
-}
-
-function RightAction(prog: SharedValue, drag: SharedValue) {
- const styleAnimation = useAnimatedStyle(() => {
- console.log('[R] showRightProgress:', prog.value);
- console.log('[R] appliedTranslation:', drag.value);
-
- return {
- transform: [{ translateX: drag.value + 50 }],
- };
- });
-
- return (
-
- Text
-
- );
-}
-
-function LegacyLeftAction(prog: any, drag: any) {
- prog.addListener((value: any) => {
- console.log('[L] showLeftProgress:', value.value);
- });
- drag.addListener((value: any) => {
- console.log('[L] appliedTranslation:', value.value);
- });
-
- const trans = Animated.subtract(drag, 50);
-
- return (
-
- Text
-
- );
-}
-
-function LegacyRightAction(prog: any, drag: any) {
- prog.addListener((value: any) => {
- console.log('[L] showRightProgress:', value.value);
- });
- drag.addListener((value: any) => {
- console.log('[L] appliedTranslation:', value.value);
- });
-
- const trans = Animated.add(drag, 50);
-
- return (
-
- Text
-
- );
-}
-
-export default function Example() {
- const reanimatedRef = useRef(null);
- const legacyRef = useRef(null);
-
- return (
-
-
-
-
- Programatical controls
-
- {
- reanimatedRef.current!.openLeft();
- legacyRef.current?.openLeft();
- }}>
- open left
-
- {
- reanimatedRef.current!.close();
- legacyRef.current!.close();
- }}>
- close
-
- {
- reanimatedRef.current!.reset();
- legacyRef.current!.reset();
- }}>
- reset
-
- {
- reanimatedRef.current!.openRight();
- legacyRef.current!.openRight();
- }}>
- open right
-
-
-
-
-
-
-
- [Reanimated] Swipe me!
-
-
-
-
-
- [Legacy] Swipe me!
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- leftAction: { width: 50, height: 50, backgroundColor: 'crimson' },
- rightAction: { width: 50, height: 50, backgroundColor: 'purple' },
- separator: {
- width: '100%',
- borderTopWidth: 1,
- },
- swipeable: {
- height: 50,
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- },
- controlPanelWrapper: {
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- },
- controlPanel: {
- backgroundColor: 'papayawhip',
- alignItems: 'center',
- flexDirection: 'row',
- },
- control: {
- flex: 1,
- height: 40,
- borderWidth: StyleSheet.hairlineWidth,
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
diff --git a/example/src/release_tests/touchables/index.tsx b/example/src/release_tests/touchables/index.tsx
index 6323f188de..67c70c70e1 100644
--- a/example/src/release_tests/touchables/index.tsx
+++ b/example/src/release_tests/touchables/index.tsx
@@ -55,7 +55,7 @@ type Touchables = {
color?: string;
renderChild: (() => null) | ((color?: string) => React.ReactNode);
text: string;
- background?: (A: typeof TouchableNativeFeedback) => BackgroundPropType;
+ background?: (A: typeof RNTouchableNativeFeedback) => BackgroundPropType;
};
const TOUCHABLES: Touchables[] = [
@@ -378,6 +378,8 @@ export class TouchableExample extends Component<
{renderChild(color)}
diff --git a/example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx b/example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx
deleted file mode 100644
index 0b4ea549b2..0000000000
--- a/example/src/showcase/swipeable/AppleStyleSwipeableRow.tsx
+++ /dev/null
@@ -1,123 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import { Animated, StyleSheet, Text, View, I18nManager } from 'react-native';
-
-import { RectButton, Swipeable } from 'react-native-gesture-handler';
-
-export default class AppleStyleSwipeableRow extends Component<
- PropsWithChildren
-> {
- private renderLeftActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const trans = dragX.interpolate({
- inputRange: [0, 50, 100, 101],
- outputRange: [-20, 0, 0, 1],
- extrapolate: 'clamp',
- });
- return (
-
-
- Archive
-
-
- );
- };
-
- private renderRightAction = (
- text: string,
- color: string,
- x: number,
- progress: Animated.AnimatedInterpolation
- ) => {
- const trans = progress.interpolate({
- inputRange: [0, 1],
- outputRange: [x, 0],
- });
- const pressHandler = () => {
- this.close();
- // eslint-disable-next-line no-alert
- window.alert(text);
- };
-
- return (
-
-
- {text}
-
-
- );
- };
-
- private renderRightActions = (
- progress: Animated.AnimatedInterpolation,
- _dragAnimatedValue: Animated.AnimatedInterpolation
- ) => (
-
- {this.renderRightAction('More', '#C8C7CD', 192, progress)}
- {this.renderRightAction('Flag', '#ffab00', 128, progress)}
- {this.renderRightAction('More', '#dd2c00', 64, progress)}
-
- );
-
- private swipeableRow?: Swipeable;
-
- private updateRef = (ref: Swipeable) => {
- this.swipeableRow = ref;
- };
- private close = () => {
- this.swipeableRow?.close();
- };
- render() {
- const { children } = this.props;
- return (
- {
- console.log(`Opening swipeable from the ${direction}`);
- }}
- onSwipeableClose={(direction) => {
- console.log(`Closing swipeable to the ${direction}`);
- }}>
- {children}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- leftAction: {
- flex: 1,
- backgroundColor: '#497AFC',
- justifyContent: 'center',
- },
- actionText: {
- color: 'white',
- fontSize: 16,
- backgroundColor: 'transparent',
- padding: 10,
- },
- rightAction: {
- alignItems: 'center',
- flex: 1,
- justifyContent: 'center',
- },
-});
diff --git a/example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx b/example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx
deleted file mode 100644
index 1504c50a70..0000000000
--- a/example/src/showcase/swipeable/GmailStyleSwipeableRow.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { Component, PropsWithChildren } from 'react';
-import { Animated, StyleSheet, I18nManager, View } from 'react-native';
-
-import { RectButton, Swipeable } from 'react-native-gesture-handler';
-
-const AnimatedView = Animated.createAnimatedComponent(View);
-
-export default class GmailStyleSwipeableRow extends Component<
- PropsWithChildren
-> {
- private renderLeftActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const scale = dragX.interpolate({
- inputRange: [0, 80],
- outputRange: [0, 1],
- extrapolate: 'clamp',
- });
- return (
-
- {/* Change it to some icons */}
-
-
- );
- };
- private renderRightActions = (
- _progress: Animated.AnimatedInterpolation,
- dragX: Animated.AnimatedInterpolation
- ) => {
- const scale = dragX.interpolate({
- inputRange: [-80, 0],
- outputRange: [1, 0],
- extrapolate: 'clamp',
- });
- return (
-
- {/* Change it to some icons */}
-
-
- );
- };
-
- private swipeableRow?: Swipeable;
-
- private updateRef = (ref: Swipeable) => {
- this.swipeableRow = ref;
- };
- private close = () => {
- this.swipeableRow?.close();
- };
- render() {
- const { children } = this.props;
- return (
-
- {children}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- leftAction: {
- flex: 1,
- backgroundColor: '#388e3c',
- justifyContent: 'flex-end',
- alignItems: 'center',
- flexDirection: I18nManager.isRTL ? 'row' : 'row-reverse',
- },
- actionIcon: {
- width: 30,
- marginHorizontal: 10,
- backgroundColor: 'plum',
- height: 20,
- },
- rightAction: {
- alignItems: 'center',
- flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
- backgroundColor: '#dd2c00',
- flex: 1,
- justifyContent: 'flex-end',
- },
-});
diff --git a/example/src/showcase/swipeable/index.tsx b/example/src/showcase/swipeable/index.tsx
deleted file mode 100644
index 5c6da6b892..0000000000
--- a/example/src/showcase/swipeable/index.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, { Component } from 'react';
-import { StyleSheet, Text, View, I18nManager } from 'react-native';
-
-import { FlatList, RectButton } from 'react-native-gesture-handler';
-
-import AppleStyleSwipeableRow from './AppleStyleSwipeableRow';
-import GmailStyleSwipeableRow from './GmailStyleSwipeableRow';
-
-// To toggle LTR/RTL change to `true`
-I18nManager.allowRTL(false);
-
-type DataRow = {
- from: string;
- when: string;
- message: string;
-};
-
-const Row = ({ item }: { item: DataRow }) => (
- // eslint-disable-next-line no-alert
- window.alert(item.from)}>
- {item.from}
-
- {item.message}
-
- {item.when} ❭
-
-);
-
-const SwipeableRow = ({ item, index }: { item: DataRow; index: number }) => {
- if (index % 2 === 0) {
- return (
-
-
-
- );
- } else {
- return (
-
-
-
- );
- }
-};
-
-export default class Example extends Component {
- render() {
- return (
- }
- renderItem={({ item, index }) => (
-
- )}
- keyExtractor={(_item, index) => `message ${index}`}
- />
- );
- }
-}
-
-const styles = StyleSheet.create({
- rectButton: {
- flex: 1,
- height: 80,
- paddingVertical: 10,
- paddingHorizontal: 20,
- justifyContent: 'space-between',
- flexDirection: 'column',
- backgroundColor: 'white',
- },
- separator: {
- backgroundColor: 'rgb(200, 199, 204)',
- height: StyleSheet.hairlineWidth,
- },
- fromText: {
- fontWeight: 'bold',
- backgroundColor: 'transparent',
- },
- messageText: {
- color: '#999',
- backgroundColor: 'transparent',
- },
- dateText: {
- backgroundColor: 'transparent',
- position: 'absolute',
- right: 20,
- top: 10,
- color: '#999',
- fontWeight: 'bold',
- },
-});
-
-const DATA: DataRow[] = [
- {
- from: "D'Artagnan",
- when: '3:11 PM',
- message:
- 'Unus pro omnibus, omnes pro uno. Nunc scelerisque, massa non lacinia porta, quam odio dapibus enim, nec tincidunt dolor leo non neque',
- },
- {
- from: 'Aramis',
- when: '11:46 AM',
- message:
- 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus hendrerit ligula dignissim maximus aliquet. Integer tincidunt, tortor at finibus molestie, ex tellus laoreet libero, lobortis consectetur nisl diam viverra justo.',
- },
- {
- from: 'Athos',
- when: '6:06 AM',
- message:
- 'Sed non arcu ullamcorper, eleifend velit eu, tristique metus. Duis id sapien eu orci varius malesuada et ac ipsum. Ut a magna vel urna tristique sagittis et dapibus augue. Vivamus non mauris a turpis auctor sagittis vitae vel ex. Curabitur accumsan quis mauris quis venenatis.',
- },
- {
- from: 'Porthos',
- when: 'Yesterday',
- message:
- 'Vivamus id condimentum lorem. Duis semper euismod luctus. Morbi maximus urna ut mi tempus fermentum. Nam eget dui sed ligula rutrum venenatis.',
- },
- {
- from: 'Domestos',
- when: '2 days ago',
- message:
- 'Aliquam imperdiet dolor eget aliquet feugiat. Fusce tincidunt mi diam. Pellentesque cursus semper sem. Aliquam ut ullamcorper massa, sed tincidunt eros.',
- },
- {
- from: 'Cardinal Richelieu',
- when: '2 days ago',
- message:
- 'Pellentesque id quam ac tortor pellentesque tempor tristique ut nunc. Pellentesque posuere ut massa eget imperdiet. Ut at nisi magna. Ut volutpat tellus ut est viverra, eu egestas ex tincidunt. Cras tellus tellus, fringilla eget massa in, ultricies maximus eros.',
- },
- {
- from: "D'Artagnan",
- when: 'Week ago',
- message:
- 'Aliquam non aliquet mi. Proin feugiat nisl maximus arcu imperdiet euismod nec at purus. Vestibulum sed dui eget mauris consequat dignissim.',
- },
- {
- from: 'Cardinal Richelieu',
- when: '2 weeks ago',
- message:
- 'Vestibulum ac nisi non augue viverra ullamcorper quis vitae mi. Donec vitae risus aliquam, posuere urna fermentum, fermentum risus. ',
- },
-];
diff --git a/example/yarn.lock b/example/yarn.lock
index 6bba886a8f..8edf36b53e 100644
--- a/example/yarn.lock
+++ b/example/yarn.lock
@@ -1049,13 +1049,6 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
-"@egjs/hammerjs@^2.0.17":
- version "2.0.17"
- resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
- integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==
- dependencies:
- "@types/hammerjs" "^2.0.36"
-
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -2264,11 +2257,6 @@
dependencies:
"@types/node" "*"
-"@types/hammerjs@^2.0.36":
- version "2.0.45"
- resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.45.tgz#ffa764bb68a66c08db6efb9c816eb7be850577b1"
- integrity sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==
-
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7"
diff --git a/package.json b/package.json
index b845580cef..8b0ac449ae 100644
--- a/package.json
+++ b/package.json
@@ -40,10 +40,8 @@
"android/reanimated/src/main/java/",
"android/noreanimated/src/main/java/",
"apple/",
- "Swipeable/",
"ReanimatedSwipeable/",
"jest-utils/",
- "DrawerLayout/",
"ReanimatedDrawerLayout/",
"README.md",
"jestSetup.js",
@@ -64,7 +62,6 @@
},
"homepage": "https://github.com/software-mansion/react-native-gesture-handler#readme",
"dependencies": {
- "@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
"invariant": "^2.2.4"
},
diff --git a/src/EnableNewWebImplementation.ts b/src/EnableNewWebImplementation.ts
deleted file mode 100644
index b519ff039c..0000000000
--- a/src/EnableNewWebImplementation.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Platform } from 'react-native';
-
-let useNewWebImplementation = true;
-let getWasCalled = false;
-
-export function enableExperimentalWebImplementation(
- _shouldEnable = true
-): void {
- // NO-OP since the new implementation is now the default
-}
-
-export function enableLegacyWebImplementation(
- shouldUseLegacyImplementation = true
-): void {
- if (
- Platform.OS !== 'web' ||
- useNewWebImplementation === !shouldUseLegacyImplementation
- ) {
- return;
- }
-
- if (getWasCalled) {
- console.error(
- 'Some parts of this application have already started using the new gesture handler implementation. No changes will be applied. You can try enabling legacy implementation earlier.'
- );
- return;
- }
-
- useNewWebImplementation = !shouldUseLegacyImplementation;
-}
-
-export function isNewWebImplementationEnabled(): boolean {
- getWasCalled = true;
- return useNewWebImplementation;
-}
diff --git a/src/RNGestureHandlerModule.web.ts b/src/RNGestureHandlerModule.web.ts
index 3812935d1b..87a9f4c188 100644
--- a/src/RNGestureHandlerModule.web.ts
+++ b/src/RNGestureHandlerModule.web.ts
@@ -1,12 +1,10 @@
import React from 'react';
import type { ActionType } from './ActionType';
-import { isNewWebImplementationEnabled } from './EnableNewWebImplementation';
-import { Gestures, HammerGestures } from './web/Gestures';
+import { Gestures } from './web/Gestures';
import type { Config } from './web/interfaces';
import InteractionManager from './web/tools/InteractionManager';
import NodeManager from './web/tools/NodeManager';
-import * as HammerNodeManager from './web_hammer/NodeManager';
import { GestureHandlerWebDelegate } from './web/tools/GestureHandlerWebDelegate';
// init method is called inside attachGestureHandler function. However, this function may
@@ -28,36 +26,21 @@ export default {
handlerTag: number,
config: T
) {
- if (isNewWebImplementationEnabled()) {
- if (!(handlerName in Gestures)) {
- throw new Error(
- `react-native-gesture-handler: ${handlerName} is not supported on web.`
- );
- }
-
- const GestureClass = Gestures[handlerName];
- NodeManager.createGestureHandler(
- handlerTag,
- new GestureClass(new GestureHandlerWebDelegate())
- );
- InteractionManager.getInstance().configureInteractions(
- NodeManager.getHandler(handlerTag),
- config as unknown as Config
+ if (!(handlerName in Gestures)) {
+ throw new Error(
+ `react-native-gesture-handler: ${handlerName} is not supported on web.`
);
- } else {
- if (!(handlerName in HammerGestures)) {
- throw new Error(
- `react-native-gesture-handler: ${handlerName} is not supported on web.`
- );
- }
-
- // @ts-ignore If it doesn't exist, the error is thrown
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
- const GestureClass = HammerGestures[handlerName];
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- HammerNodeManager.createGestureHandler(handlerTag, new GestureClass());
}
+ const GestureClass = Gestures[handlerName];
+ NodeManager.createGestureHandler(
+ handlerTag,
+ new GestureClass(new GestureHandlerWebDelegate())
+ );
+ InteractionManager.getInstance().configureInteractions(
+ NodeManager.getHandler(handlerTag),
+ config as unknown as Config
+ );
this.updateGestureHandler(handlerTag, config as unknown as Config);
},
attachGestureHandler(
@@ -70,9 +53,7 @@ export default {
if (!(newView instanceof Element || newView instanceof React.Component)) {
shouldPreventDrop = true;
- const handler = isNewWebImplementationEnabled()
- ? NodeManager.getHandler(handlerTag)
- : HammerNodeManager.getHandler(handlerTag);
+ const handler = NodeManager.getHandler(handlerTag);
const handlerName = handler.constructor.name;
@@ -81,43 +62,26 @@ export default {
);
}
- if (isNewWebImplementationEnabled()) {
- // @ts-ignore Types should be HTMLElement or React.Component
- NodeManager.getHandler(handlerTag).init(newView, propsRef);
- } else {
- // @ts-ignore Types should be HTMLElement or React.Component
- HammerNodeManager.getHandler(handlerTag).setView(newView, propsRef);
- }
+ // @ts-ignore Types should be HTMLElement or React.Component
+ NodeManager.getHandler(handlerTag).init(newView, propsRef);
},
updateGestureHandler(handlerTag: number, newConfig: Config) {
- if (isNewWebImplementationEnabled()) {
- NodeManager.getHandler(handlerTag).updateGestureConfig(newConfig);
+ NodeManager.getHandler(handlerTag).updateGestureConfig(newConfig);
- InteractionManager.getInstance().configureInteractions(
- NodeManager.getHandler(handlerTag),
- newConfig
- );
- } else {
- HammerNodeManager.getHandler(handlerTag).updateGestureConfig(newConfig);
- }
+ InteractionManager.getInstance().configureInteractions(
+ NodeManager.getHandler(handlerTag),
+ newConfig
+ );
},
getGestureHandlerNode(handlerTag: number) {
- if (isNewWebImplementationEnabled()) {
- return NodeManager.getHandler(handlerTag);
- } else {
- return HammerNodeManager.getHandler(handlerTag);
- }
+ return NodeManager.getHandler(handlerTag);
},
dropGestureHandler(handlerTag: number) {
if (shouldPreventDrop) {
return;
}
- if (isNewWebImplementationEnabled()) {
- NodeManager.dropGestureHandler(handlerTag);
- } else {
- HammerNodeManager.dropGestureHandler(handlerTag);
- }
+ NodeManager.dropGestureHandler(handlerTag);
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
flushOperations() {},
diff --git a/src/components/DrawerLayout.tsx b/src/components/DrawerLayout.tsx
deleted file mode 100644
index 5708e30d9d..0000000000
--- a/src/components/DrawerLayout.tsx
+++ /dev/null
@@ -1,756 +0,0 @@
-// This component is based on RN's DrawerLayoutAndroid API
-//
-// It perhaps deserves to be put in a separate repo, but since it relies on
-// react-native-gesture-handler library which isn't very popular at the moment I
-// decided to keep it here for the time being. It will allow us to move faster
-// and fix issues that may arise in gesture handler library that could be found
-// when using the drawer component
-
-import * as React from 'react';
-import { Component } from 'react';
-import invariant from 'invariant';
-import {
- Animated,
- StyleSheet,
- View,
- Keyboard,
- StatusBar,
- I18nManager,
- StatusBarAnimation,
- StyleProp,
- ViewStyle,
- LayoutChangeEvent,
- NativeSyntheticEvent,
-} from 'react-native';
-
-import {
- GestureEvent,
- HandlerStateChangeEvent,
- UserSelect,
- ActiveCursor,
- MouseButton,
-} from '../handlers/gestureHandlerCommon';
-import { PanGestureHandler } from '../handlers/PanGestureHandler';
-import type {
- PanGestureHandlerEventPayload,
- TapGestureHandlerEventPayload,
-} from '../handlers/GestureHandlerEventPayload';
-import { TapGestureHandler } from '../handlers/TapGestureHandler';
-import { State } from '../State';
-
-const DRAG_TOSS = 0.05;
-
-const IDLE: DrawerState = 'Idle';
-const DRAGGING: DrawerState = 'Dragging';
-const SETTLING: DrawerState = 'Settling';
-
-export type DrawerPosition = 'left' | 'right';
-
-export type DrawerState = 'Idle' | 'Dragging' | 'Settling';
-
-export type DrawerType = 'front' | 'back' | 'slide';
-
-export type DrawerLockMode = 'unlocked' | 'locked-closed' | 'locked-open';
-
-export type DrawerKeyboardDismissMode = 'none' | 'on-drag';
-
-// Animated.AnimatedInterpolation has been converted to a generic type
-// in @types/react-native 0.70. This way we can maintain compatibility
-// with all versions of @types/react-native`
-type AnimatedInterpolation = ReturnType;
-export interface DrawerLayoutProps {
- /**
- * This attribute is present in the standard implementation already and is one
- * of the required params. Gesture handler version of DrawerLayout make it
- * possible for the function passed as `renderNavigationView` to take an
- * Animated value as a parameter that indicates the progress of drawer
- * opening/closing animation (progress value is 0 when closed and 1 when
- * opened). This can be used by the drawer component to animated its children
- * while the drawer is opening or closing.
- */
- renderNavigationView: (
- progressAnimatedValue: Animated.Value
- ) => React.ReactNode;
-
- drawerPosition?: DrawerPosition;
-
- drawerWidth?: number;
-
- drawerBackgroundColor?: string;
-
- drawerLockMode?: DrawerLockMode;
-
- keyboardDismissMode?: DrawerKeyboardDismissMode;
-
- /**
- * Called when the drawer is closed.
- */
- onDrawerClose?: () => void;
-
- /**
- * Called when the drawer is opened.
- */
- onDrawerOpen?: () => void;
-
- /**
- * Called when the status of the drawer changes.
- */
- onDrawerStateChanged?: (
- newState: DrawerState,
- drawerWillShow: boolean
- ) => void;
- useNativeAnimations?: boolean;
-
- drawerType?: DrawerType;
-
- /**
- * Defines how far from the edge of the content view the gesture should
- * activate.
- */
- edgeWidth?: number;
-
- minSwipeDistance?: number;
-
- /**
- * When set to true Drawer component will use
- * {@link https://reactnative.dev/docs/statusbar StatusBar} API to hide the OS
- * status bar whenever the drawer is pulled or when its in an "open" state.
- */
- hideStatusBar?: boolean;
-
- /**
- * @default 'slide'
- *
- * Can be used when hideStatusBar is set to true and will select the animation
- * used for hiding/showing the status bar. See
- * {@link https://reactnative.dev/docs/statusbar StatusBar} documentation for
- * more details
- */
- statusBarAnimation?: StatusBarAnimation;
-
- /**
- * @default black
- *
- * Color of a semi-transparent overlay to be displayed on top of the content
- * view when drawer gets open. A solid color should be used as the opacity is
- * added by the Drawer itself and the opacity of the overlay is animated (from
- * 0% to 70%).
- */
- overlayColor?: string;
-
- contentContainerStyle?: StyleProp;
-
- drawerContainerStyle?: StyleProp;
-
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- onDrawerSlide?: (position: number) => void;
-
- onGestureRef?: (ref: PanGestureHandler) => void;
-
- // Implicit `children` prop has been removed in @types/react^18.0.0
- children?:
- | React.ReactNode
- | ((openValue?: AnimatedInterpolation) => React.ReactNode);
-
- /**
- * @default 'none'
- * Defines which userSelect property should be used.
- * Values: 'none'|'text'|'auto'
- */
- userSelect?: UserSelect;
-
- /**
- * @default 'auto'
- * Defines which cursor property should be used when gesture activates.
- * Values: see CSS cursor values
- */
- activeCursor?: ActiveCursor;
-
- /**
- * @default 'MouseButton.LEFT'
- * Allows to choose which mouse button should underlying pan handler react to.
- */
- mouseButton?: MouseButton;
-
- /**
- * @default 'false if MouseButton.RIGHT is specified'
- * Allows to enable/disable context menu.
- */
- enableContextMenu?: boolean;
-}
-
-export type DrawerLayoutState = {
- dragX: Animated.Value;
- touchX: Animated.Value;
- drawerTranslation: Animated.Value;
- containerWidth: number;
- drawerState: DrawerState;
- drawerOpened: boolean;
-};
-
-export type DrawerMovementOption = {
- velocity?: number;
- speed?: number;
-};
-export default class DrawerLayout extends Component<
- DrawerLayoutProps,
- DrawerLayoutState
-> {
- static defaultProps = {
- drawerWidth: 200,
- drawerPosition: 'left',
- useNativeAnimations: true,
- drawerType: 'front',
- edgeWidth: 20,
- minSwipeDistance: 3,
- overlayColor: 'rgba(0, 0, 0, 0.7)',
- drawerLockMode: 'unlocked',
- enableTrackpadTwoFingerGesture: false,
- };
-
- constructor(props: DrawerLayoutProps) {
- super(props);
-
- const dragX = new Animated.Value(0);
- const touchX = new Animated.Value(0);
- const drawerTranslation = new Animated.Value(0);
-
- this.state = {
- dragX,
- touchX,
- drawerTranslation,
- containerWidth: 0,
- drawerState: IDLE,
- drawerOpened: false,
- };
-
- this.updateAnimatedEvent(props, this.state);
- }
-
- shouldComponentUpdate(props: DrawerLayoutProps, state: DrawerLayoutState) {
- if (
- this.props.drawerPosition !== props.drawerPosition ||
- this.props.drawerWidth !== props.drawerWidth ||
- this.props.drawerType !== props.drawerType ||
- this.state.containerWidth !== state.containerWidth
- ) {
- this.updateAnimatedEvent(props, state);
- }
-
- return true;
- }
-
- private openValue?: AnimatedInterpolation;
- private onGestureEvent?: (
- event: GestureEvent
- ) => void;
- private accessibilityIsModalView = React.createRef();
- private pointerEventsView = React.createRef();
- private panGestureHandler = React.createRef();
- private drawerShown = false;
-
- static positions = {
- Left: 'left',
- Right: 'right',
- };
-
- private updateAnimatedEvent = (
- props: DrawerLayoutProps,
- state: DrawerLayoutState
- ) => {
- // Event definition is based on
- const { drawerPosition, drawerWidth, drawerType } = props;
- const {
- dragX: dragXValue,
- touchX: touchXValue,
- drawerTranslation,
- containerWidth,
- } = state;
-
- let dragX = dragXValue;
- let touchX = touchXValue;
-
- if (drawerPosition !== 'left') {
- // Most of the code is written in a way to handle left-side drawer. In
- // order to handle right-side drawer the only thing we need to do is to
- // reverse events coming from gesture handler in a way they emulate
- // left-side drawer gestures. E.g. dragX is simply -dragX, and touchX is
- // calulcated by subtracing real touchX from the width of the container
- // (such that when touch happens at the right edge the value is simply 0)
- dragX = Animated.multiply(
- new Animated.Value(-1),
- dragXValue
- ) as Animated.Value; // TODO(TS): (for all "as" in this file) make sure we can map this
- touchX = Animated.add(
- new Animated.Value(containerWidth),
- Animated.multiply(new Animated.Value(-1), touchXValue)
- ) as Animated.Value; // TODO(TS): make sure we can map this;
- touchXValue.setValue(containerWidth);
- } else {
- touchXValue.setValue(0);
- }
-
- // While closing the drawer when user starts gesture outside of its area (in greyed
- // out part of the window), we want the drawer to follow only once finger reaches the
- // edge of the drawer.
- // E.g. on the diagram below drawer is illustrate by X signs and the greyed out area by
- // dots. The touch gesture starts at '*' and moves left, touch path is indicated by
- // an arrow pointing left
- // 1) +---------------+ 2) +---------------+ 3) +---------------+ 4) +---------------+
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|.<-*..| |XXXXXXXX|<--*..| |XXXXX|<-----*..|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // |XXXXXXXX|......| |XXXXXXXX|......| |XXXXXXXX|......| |XXXXX|.........|
- // +---------------+ +---------------+ +---------------+ +---------------+
- //
- // For the above to work properly we define animated value that will keep
- // start position of the gesture. Then we use that value to calculate how
- // much we need to subtract from the dragX. If the gesture started on the
- // greyed out area we take the distance from the edge of the drawer to the
- // start position. Otherwise we don't subtract at all and the drawer be
- // pulled back as soon as you start the pan.
- //
- // This is used only when drawerType is "front"
- //
- let translationX = dragX;
- if (drawerType === 'front') {
- const startPositionX = Animated.add(
- touchX,
- Animated.multiply(new Animated.Value(-1), dragX)
- );
-
- const dragOffsetFromOnStartPosition = startPositionX.interpolate({
- inputRange: [drawerWidth! - 1, drawerWidth!, drawerWidth! + 1],
- outputRange: [0, 0, 1],
- });
- translationX = Animated.add(
- dragX,
- dragOffsetFromOnStartPosition
- ) as Animated.Value; // TODO: as above
- }
-
- this.openValue = Animated.add(translationX, drawerTranslation).interpolate({
- inputRange: [0, drawerWidth!],
- outputRange: [0, 1],
- extrapolate: 'clamp',
- });
-
- const gestureOptions: {
- useNativeDriver: boolean;
- // TODO: make sure it is correct
- listener?: (
- ev: NativeSyntheticEvent
- ) => void;
- } = {
- useNativeDriver: props.useNativeAnimations!,
- };
-
- if (this.props.onDrawerSlide) {
- gestureOptions.listener = (ev) => {
- const translationX = Math.floor(Math.abs(ev.nativeEvent.translationX));
- const position = translationX / this.state.containerWidth;
-
- this.props.onDrawerSlide?.(position);
- };
- }
-
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: dragXValue, x: touchXValue } }],
- gestureOptions
- );
- };
-
- private handleContainerLayout = ({ nativeEvent }: LayoutChangeEvent) => {
- this.setState({ containerWidth: nativeEvent.layout.width });
- };
-
- private emitStateChanged = (
- newState: DrawerState,
- drawerWillShow: boolean
- ) => {
- this.props.onDrawerStateChanged?.(newState, drawerWillShow);
- };
-
- private openingHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (nativeEvent.oldState === State.ACTIVE) {
- this.handleRelease({ nativeEvent });
- } else if (nativeEvent.state === State.ACTIVE) {
- this.emitStateChanged(DRAGGING, false);
- this.setState({ drawerState: DRAGGING });
- if (this.props.keyboardDismissMode === 'on-drag') {
- Keyboard.dismiss();
- }
- if (this.props.hideStatusBar) {
- StatusBar.setHidden(true, this.props.statusBarAnimation || 'slide');
- }
- }
- };
-
- private onTapHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (
- this.drawerShown &&
- nativeEvent.oldState === State.ACTIVE &&
- this.props.drawerLockMode !== 'locked-open'
- ) {
- this.closeDrawer();
- }
- };
-
- private handleRelease = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- const { drawerWidth, drawerPosition, drawerType } = this.props;
- const { containerWidth } = this.state;
- let { translationX: dragX, velocityX, x: touchX } = nativeEvent;
-
- if (drawerPosition !== 'left') {
- // See description in _updateAnimatedEvent about why events are flipped
- // for right-side drawer
- dragX = -dragX;
- touchX = containerWidth - touchX;
- velocityX = -velocityX;
- }
-
- const gestureStartX = touchX - dragX;
- let dragOffsetBasedOnStart = 0;
-
- if (drawerType === 'front') {
- dragOffsetBasedOnStart =
- gestureStartX > drawerWidth! ? gestureStartX - drawerWidth! : 0;
- }
-
- const startOffsetX =
- dragX + dragOffsetBasedOnStart + (this.drawerShown ? drawerWidth! : 0);
- const projOffsetX = startOffsetX + DRAG_TOSS * velocityX;
-
- const shouldOpen = projOffsetX > drawerWidth! / 2;
-
- if (shouldOpen) {
- this.animateDrawer(startOffsetX, drawerWidth!, velocityX);
- } else {
- this.animateDrawer(startOffsetX, 0, velocityX);
- }
- };
-
- private updateShowing = (showing: boolean) => {
- this.drawerShown = showing;
- this.accessibilityIsModalView.current?.setNativeProps({
- accessibilityViewIsModal: showing,
- });
- this.pointerEventsView.current?.setNativeProps({
- pointerEvents: showing ? 'auto' : 'none',
- });
- const { drawerPosition, minSwipeDistance, edgeWidth } = this.props;
- const fromLeft = drawerPosition === 'left';
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation =
- (fromLeft ? 1 : -1) * (this.drawerShown ? -1 : 1);
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: showing ? undefined : edgeWidth }
- : { right: 0, width: showing ? undefined : edgeWidth };
- // @ts-ignore internal API, maybe could be fixed in handler types
- this.panGestureHandler.current?.setNativeProps({
- hitSlop,
- activeOffsetX: gestureOrientation * minSwipeDistance!,
- });
- };
-
- private animateDrawer = (
- fromValue: number | null | undefined,
- toValue: number,
- velocity: number,
- speed?: number
- ) => {
- this.state.dragX.setValue(0);
- this.state.touchX.setValue(
- this.props.drawerPosition === 'left' ? 0 : this.state.containerWidth
- );
-
- if (fromValue != null) {
- let nextFramePosition = fromValue;
- if (this.props.useNativeAnimations) {
- // When using native driver, we predict the next position of the
- // animation because it takes one frame of a roundtrip to pass RELEASE
- // event from native driver to JS before we can start animating. Without
- // it, it is more noticable that the frame is dropped.
- if (fromValue < toValue && velocity > 0) {
- nextFramePosition = Math.min(fromValue + velocity / 60.0, toValue);
- } else if (fromValue > toValue && velocity < 0) {
- nextFramePosition = Math.max(fromValue + velocity / 60.0, toValue);
- }
- }
- this.state.drawerTranslation.setValue(nextFramePosition);
- }
-
- const willShow = toValue !== 0;
- this.updateShowing(willShow);
- this.emitStateChanged(SETTLING, willShow);
- this.setState({ drawerState: SETTLING });
- if (this.props.hideStatusBar) {
- StatusBar.setHidden(willShow, this.props.statusBarAnimation || 'slide');
- }
- Animated.spring(this.state.drawerTranslation, {
- velocity,
- bounciness: 0,
- toValue,
- useNativeDriver: this.props.useNativeAnimations!,
- speed: speed ?? undefined,
- }).start(({ finished }) => {
- if (finished) {
- this.emitStateChanged(IDLE, willShow);
- this.setState({ drawerOpened: willShow });
- if (this.state.drawerState !== DRAGGING) {
- // It's possilbe that user started drag while the drawer
- // was settling, don't override state in this case
- this.setState({ drawerState: IDLE });
- }
- if (willShow) {
- this.props.onDrawerOpen?.();
- } else {
- this.props.onDrawerClose?.();
- }
- }
- });
- };
-
- openDrawer = (options: DrawerMovementOption = {}) => {
- this.animateDrawer(
- // TODO: decide if it should be null or undefined is the proper value
- undefined,
- this.props.drawerWidth!,
- options.velocity ? options.velocity : 0,
- options.speed
- );
-
- // We need to force the update, otherwise the overlay is not rerendered and
- // it would not be clickable
- this.forceUpdate();
- };
-
- closeDrawer = (options: DrawerMovementOption = {}) => {
- // TODO: decide if it should be null or undefined is the proper value
- this.animateDrawer(
- undefined,
- 0,
- options.velocity ? options.velocity : 0,
- options.speed
- );
-
- // We need to force the update, otherwise the overlay is not rerendered and
- // it would be still clickable
- this.forceUpdate();
- };
-
- private renderOverlay = () => {
- /* Overlay styles */
- invariant(this.openValue, 'should be set');
- let overlayOpacity;
-
- if (this.state.drawerState !== IDLE) {
- overlayOpacity = this.openValue;
- } else {
- overlayOpacity = this.state.drawerOpened ? 1 : 0;
- }
-
- const dynamicOverlayStyles = {
- opacity: overlayOpacity,
- backgroundColor: this.props.overlayColor,
- };
-
- return (
-
-
-
- );
- };
-
- private renderDrawer = () => {
- const {
- drawerBackgroundColor,
- drawerWidth,
- drawerPosition,
- drawerType,
- drawerContainerStyle,
- contentContainerStyle,
- } = this.props;
-
- const fromLeft = drawerPosition === 'left';
- const drawerSlide = drawerType !== 'back';
- const containerSlide = drawerType !== 'front';
-
- // We rely on row and row-reverse flex directions to position the drawer
- // properly. Apparently for RTL these are flipped which requires us to use
- // the opposite setting for the drawer to appear from left or right
- // according to the drawerPosition prop
- const reverseContentDirection = I18nManager.isRTL ? fromLeft : !fromLeft;
-
- const dynamicDrawerStyles = {
- backgroundColor: drawerBackgroundColor,
- width: drawerWidth,
- };
- const openValue = this.openValue;
- invariant(openValue, 'should be set');
-
- let containerStyles;
- if (containerSlide) {
- const containerTranslateX = openValue.interpolate({
- inputRange: [0, 1],
- outputRange: fromLeft ? [0, drawerWidth!] : [0, -drawerWidth!],
- extrapolate: 'clamp',
- });
- containerStyles = {
- transform: [{ translateX: containerTranslateX }],
- };
- }
-
- let drawerTranslateX: number | AnimatedInterpolation = 0;
- if (drawerSlide) {
- const closedDrawerOffset = fromLeft ? -drawerWidth! : drawerWidth!;
- if (this.state.drawerState !== IDLE) {
- drawerTranslateX = openValue.interpolate({
- inputRange: [0, 1],
- outputRange: [closedDrawerOffset, 0],
- extrapolate: 'clamp',
- });
- } else {
- drawerTranslateX = this.state.drawerOpened ? 0 : closedDrawerOffset;
- }
- }
- const drawerStyles: {
- transform: { translateX: number | AnimatedInterpolation }[];
- flexDirection: 'row-reverse' | 'row';
- } = {
- transform: [{ translateX: drawerTranslateX }],
- flexDirection: reverseContentDirection ? 'row-reverse' : 'row',
- };
-
- return (
-
-
- {typeof this.props.children === 'function'
- ? this.props.children(this.openValue)
- : this.props.children}
- {this.renderOverlay()}
-
-
-
- {this.props.renderNavigationView(this.openValue as Animated.Value)}
-
-
-
- );
- };
-
- private setPanGestureRef = (ref: PanGestureHandler) => {
- // TODO(TS): make sure it is OK taken from
- // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31065#issuecomment-596081842
- (
- this.panGestureHandler as React.MutableRefObject
- ).current = ref;
- this.props.onGestureRef?.(ref);
- };
-
- render() {
- const { drawerPosition, drawerLockMode, edgeWidth, minSwipeDistance } =
- this.props;
-
- const fromLeft = drawerPosition === 'left';
-
- // gestureOrientation is 1 if the expected gesture is from left to right and
- // -1 otherwise e.g. when drawer is on the left and is closed we expect left
- // to right gesture, thus orientation will be 1.
- const gestureOrientation =
- (fromLeft ? 1 : -1) * (this.drawerShown ? -1 : 1);
-
- // When drawer is closed we want the hitSlop to be horizontally shorter than
- // the container size by the value of SLOP. This will make it only activate
- // when gesture happens not further than SLOP away from the edge
- const hitSlop = fromLeft
- ? { left: 0, width: this.drawerShown ? undefined : edgeWidth }
- : { right: 0, width: this.drawerShown ? undefined : edgeWidth };
-
- return (
-
- {this.renderDrawer()}
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- drawerContainer: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1001,
- flexDirection: 'row',
- },
- containerInFront: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1002,
- },
- containerOnBack: {
- ...StyleSheet.absoluteFillObject,
- },
- main: {
- flex: 1,
- zIndex: 0,
- overflow: 'hidden',
- },
- overlay: {
- ...StyleSheet.absoluteFillObject,
- zIndex: 1000,
- },
-});
diff --git a/src/components/Swipeable.tsx b/src/components/Swipeable.tsx
deleted file mode 100644
index 593ab59740..0000000000
--- a/src/components/Swipeable.tsx
+++ /dev/null
@@ -1,592 +0,0 @@
-// Similarily to the DrawerLayout component this deserves to be put in a
-// separate repo. Although, keeping it here for the time being will allow us to
-// move faster and fix possible issues quicker
-
-import * as React from 'react';
-import { Component } from 'react';
-import {
- Animated,
- StyleSheet,
- View,
- I18nManager,
- LayoutChangeEvent,
- StyleProp,
- ViewStyle,
-} from 'react-native';
-
-import {
- GestureEvent,
- HandlerStateChangeEvent,
-} from '../handlers/gestureHandlerCommon';
-import {
- PanGestureHandler,
- PanGestureHandlerProps,
-} from '../handlers/PanGestureHandler';
-import {
- PanGestureHandlerEventPayload,
- TapGestureHandlerEventPayload,
-} from '../handlers/GestureHandlerEventPayload';
-import { TapGestureHandler } from '../handlers/TapGestureHandler';
-import { State } from '../State';
-
-const DRAG_TOSS = 0.05;
-
-type SwipeableExcludes = Exclude<
- keyof PanGestureHandlerProps,
- 'onGestureEvent' | 'onHandlerStateChange'
->;
-
-// Animated.AnimatedInterpolation has been converted to a generic type
-// in @types/react-native 0.70. This way we can maintain compatibility
-// with all versions of @types/react-native
-type AnimatedInterpolation = ReturnType;
-
-export interface SwipeableProps
- extends Pick {
- /**
- * Enables two-finger gestures on supported devices, for example iPads with
- * trackpads. If not enabled the gesture will require click + drag, with
- * `enableTrackpadTwoFingerGesture` swiping with two fingers will also trigger
- * the gesture.
- */
- enableTrackpadTwoFingerGesture?: boolean;
-
- /**
- * Specifies how much the visual interaction will be delayed compared to the
- * gesture distance. e.g. value of 1 will indicate that the swipeable panel
- * should exactly follow the gesture, 2 means it is going to be two times
- * "slower".
- */
- friction?: number;
-
- /**
- * Distance from the left edge at which released panel will animate to the
- * open state (or the open panel will animate into the closed state). By
- * default it's a half of the panel's width.
- */
- leftThreshold?: number;
-
- /**
- * Distance from the right edge at which released panel will animate to the
- * open state (or the open panel will animate into the closed state). By
- * default it's a half of the panel's width.
- */
- rightThreshold?: number;
-
- /**
- * Distance that the panel must be dragged from the left edge to be considered
- * a swipe. The default value is 10.
- */
- dragOffsetFromLeftEdge?: number;
-
- /**
- * Distance that the panel must be dragged from the right edge to be considered
- * a swipe. The default value is 10.
- */
- dragOffsetFromRightEdge?: number;
-
- /**
- * Value indicating if the swipeable panel can be pulled further than the left
- * actions panel's width. It is set to true by default as long as the left
- * panel render method is present.
- */
- overshootLeft?: boolean;
-
- /**
- * Value indicating if the swipeable panel can be pulled further than the
- * right actions panel's width. It is set to true by default as long as the
- * right panel render method is present.
- */
- overshootRight?: boolean;
-
- /**
- * Specifies how much the visual interaction will be delayed compared to the
- * gesture distance at overshoot. Default value is 1, it mean no friction, for
- * a native feel, try 8 or above.
- */
- overshootFriction?: number;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableOpen()
- *
- * Called when left action panel gets open.
- */
- onSwipeableLeftOpen?: () => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableOpen()
- *
- * Called when right action panel gets open.
- */
- onSwipeableRightOpen?: () => void;
-
- /**
- * Called when action panel gets open (either right or left).
- */
- onSwipeableOpen?: (direction: 'left' | 'right', swipeable: Swipeable) => void;
-
- /**
- * Called when action panel is closed.
- */
- onSwipeableClose?: (
- direction: 'left' | 'right',
- swipeable: Swipeable
- ) => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableWillOpen()
- *
- * Called when left action panel starts animating on open.
- */
- onSwipeableLeftWillOpen?: () => void;
-
- /**
- * @deprecated Use `direction` argument of onSwipeableWillOpen()
- *
- * Called when right action panel starts animating on open.
- */
- onSwipeableRightWillOpen?: () => void;
-
- /**
- * Called when action panel starts animating on open (either right or left).
- */
- onSwipeableWillOpen?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts animating on close.
- */
- onSwipeableWillClose?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts being shown on dragging to open.
- */
- onSwipeableOpenStartDrag?: (direction: 'left' | 'right') => void;
-
- /**
- * Called when action panel starts being shown on dragging to close.
- */
- onSwipeableCloseStartDrag?: (direction: 'left' | 'right') => void;
-
- /**
- *
- * This map describes the values to use as inputRange for extra interpolation:
- * AnimatedValue: [startValue, endValue]
- *
- * progressAnimatedValue: [0, 1] dragAnimatedValue: [0, +]
- *
- * To support `rtl` flexbox layouts use `flexDirection` styling.
- * */
- renderLeftActions?: (
- progressAnimatedValue: AnimatedInterpolation,
- dragAnimatedValue: AnimatedInterpolation,
- swipeable: Swipeable
- ) => React.ReactNode;
- /**
- *
- * This map describes the values to use as inputRange for extra interpolation:
- * AnimatedValue: [startValue, endValue]
- *
- * progressAnimatedValue: [0, 1] dragAnimatedValue: [0, -]
- *
- * To support `rtl` flexbox layouts use `flexDirection` styling.
- * */
- renderRightActions?: (
- progressAnimatedValue: AnimatedInterpolation,
- dragAnimatedValue: AnimatedInterpolation,
- swipeable: Swipeable
- ) => React.ReactNode;
-
- useNativeAnimations?: boolean;
-
- animationOptions?: Record;
-
- /**
- * Style object for the container (`Animated.View`), for example to override
- * `overflow: 'hidden'`.
- */
- containerStyle?: StyleProp;
-
- /**
- * Style object for the children container (`Animated.View`), for example to
- * apply `flex: 1`
- */
- childrenContainerStyle?: StyleProp;
-}
-
-type SwipeableState = {
- dragX: Animated.Value;
- rowTranslation: Animated.Value;
- rowState: number;
- leftWidth?: number;
- rightOffset?: number;
- rowWidth?: number;
-};
-
-/**
- * @deprecated use Reanimated version of Swipeable instead
- *
- * This component allows for implementing swipeable rows or similar interaction.
- */
-
-export default class Swipeable extends Component<
- SwipeableProps,
- SwipeableState
-> {
- static defaultProps = {
- friction: 1,
- overshootFriction: 1,
- useNativeAnimations: true,
- };
-
- constructor(props: SwipeableProps) {
- super(props);
- const dragX = new Animated.Value(0);
- this.state = {
- dragX,
- rowTranslation: new Animated.Value(0),
- rowState: 0,
- leftWidth: undefined,
- rightOffset: undefined,
- rowWidth: undefined,
- };
- this.updateAnimatedEvent(props, this.state);
-
- this.onGestureEvent = Animated.event(
- [{ nativeEvent: { translationX: dragX } }],
- { useNativeDriver: props.useNativeAnimations! }
- );
- }
-
- shouldComponentUpdate(props: SwipeableProps, state: SwipeableState) {
- if (
- this.props.friction !== props.friction ||
- this.props.overshootLeft !== props.overshootLeft ||
- this.props.overshootRight !== props.overshootRight ||
- this.props.overshootFriction !== props.overshootFriction ||
- this.state.leftWidth !== state.leftWidth ||
- this.state.rightOffset !== state.rightOffset ||
- this.state.rowWidth !== state.rowWidth
- ) {
- this.updateAnimatedEvent(props, state);
- }
-
- return true;
- }
-
- private onGestureEvent?: (
- event: GestureEvent
- ) => void;
- private transX?: AnimatedInterpolation;
- private showLeftAction?: AnimatedInterpolation | Animated.Value;
- private leftActionTranslate?: AnimatedInterpolation;
- private showRightAction?: AnimatedInterpolation | Animated.Value;
- private rightActionTranslate?: AnimatedInterpolation;
-
- private updateAnimatedEvent = (
- props: SwipeableProps,
- state: SwipeableState
- ) => {
- const { friction, overshootFriction } = props;
- const { dragX, rowTranslation, leftWidth = 0, rowWidth = 0 } = state;
- const { rightOffset = rowWidth } = state;
- const rightWidth = Math.max(0, rowWidth - rightOffset);
-
- const { overshootLeft = leftWidth > 0, overshootRight = rightWidth > 0 } =
- props;
-
- const transX = Animated.add(
- rowTranslation,
- dragX.interpolate({
- inputRange: [0, friction!],
- outputRange: [0, 1],
- })
- ).interpolate({
- inputRange: [-rightWidth - 1, -rightWidth, leftWidth, leftWidth + 1],
- outputRange: [
- -rightWidth - (overshootRight ? 1 / overshootFriction! : 0),
- -rightWidth,
- leftWidth,
- leftWidth + (overshootLeft ? 1 / overshootFriction! : 0),
- ],
- });
- this.transX = transX;
- this.showLeftAction =
- leftWidth > 0
- ? transX.interpolate({
- inputRange: [-1, 0, leftWidth],
- outputRange: [0, 0, 1],
- })
- : new Animated.Value(0);
- this.leftActionTranslate = this.showLeftAction.interpolate({
- inputRange: [0, Number.MIN_VALUE],
- outputRange: [-10000, 0],
- extrapolate: 'clamp',
- });
- this.showRightAction =
- rightWidth > 0
- ? transX.interpolate({
- inputRange: [-rightWidth, 0, 1],
- outputRange: [1, 0, 0],
- })
- : new Animated.Value(0);
- this.rightActionTranslate = this.showRightAction.interpolate({
- inputRange: [0, Number.MIN_VALUE],
- outputRange: [-10000, 0],
- extrapolate: 'clamp',
- });
- };
-
- private onTapHandlerStateChange = ({
- nativeEvent,
- }: HandlerStateChangeEvent) => {
- if (nativeEvent.oldState === State.ACTIVE) {
- this.close();
- }
- };
-
- private onHandlerStateChange = (
- ev: HandlerStateChangeEvent
- ) => {
- if (ev.nativeEvent.oldState === State.ACTIVE) {
- this.handleRelease(ev);
- }
-
- if (ev.nativeEvent.state === State.ACTIVE) {
- const { velocityX, translationX: dragX } = ev.nativeEvent;
- const { rowState } = this.state;
- const { friction } = this.props;
-
- const translationX = (dragX + DRAG_TOSS * velocityX) / friction!;
-
- const direction =
- rowState === -1
- ? 'right'
- : rowState === 1
- ? 'left'
- : translationX > 0
- ? 'left'
- : 'right';
-
- if (rowState === 0) {
- this.props.onSwipeableOpenStartDrag?.(direction);
- } else {
- this.props.onSwipeableCloseStartDrag?.(direction);
- }
- }
- };
-
- private handleRelease = (
- ev: HandlerStateChangeEvent
- ) => {
- const { velocityX, translationX: dragX } = ev.nativeEvent;
- const { leftWidth = 0, rowWidth = 0, rowState } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- const {
- friction,
- leftThreshold = leftWidth / 2,
- rightThreshold = rightWidth / 2,
- } = this.props;
-
- const startOffsetX = this.currentOffset() + dragX / friction!;
- const translationX = (dragX + DRAG_TOSS * velocityX) / friction!;
-
- let toValue = 0;
- if (rowState === 0) {
- if (translationX > leftThreshold) {
- toValue = leftWidth;
- } else if (translationX < -rightThreshold) {
- toValue = -rightWidth;
- }
- } else if (rowState === 1) {
- // Swiped to left
- if (translationX > -leftThreshold) {
- toValue = leftWidth;
- }
- } else {
- // Swiped to right
- if (translationX < rightThreshold) {
- toValue = -rightWidth;
- }
- }
-
- this.animateRow(startOffsetX, toValue, velocityX / friction!);
- };
-
- private animateRow = (
- fromValue: number,
- toValue: number,
- velocityX?:
- | number
- | {
- x: number;
- y: number;
- }
- ) => {
- const { dragX, rowTranslation } = this.state;
- dragX.setValue(0);
- rowTranslation.setValue(fromValue);
-
- this.setState({ rowState: Math.sign(toValue) });
- Animated.spring(rowTranslation, {
- restSpeedThreshold: 1.7,
- restDisplacementThreshold: 0.4,
- velocity: velocityX,
- bounciness: 0,
- toValue,
- useNativeDriver: this.props.useNativeAnimations!,
- ...this.props.animationOptions,
- }).start(({ finished }) => {
- if (finished) {
- if (toValue > 0) {
- this.props.onSwipeableLeftOpen?.();
- this.props.onSwipeableOpen?.('left', this);
- } else if (toValue < 0) {
- this.props.onSwipeableRightOpen?.();
- this.props.onSwipeableOpen?.('right', this);
- } else {
- const closingDirection = fromValue > 0 ? 'left' : 'right';
- this.props.onSwipeableClose?.(closingDirection, this);
- }
- }
- });
- if (toValue > 0) {
- this.props.onSwipeableLeftWillOpen?.();
- this.props.onSwipeableWillOpen?.('left');
- } else if (toValue < 0) {
- this.props.onSwipeableRightWillOpen?.();
- this.props.onSwipeableWillOpen?.('right');
- } else {
- const closingDirection = fromValue > 0 ? 'left' : 'right';
- this.props.onSwipeableWillClose?.(closingDirection);
- }
- };
-
- private onRowLayout = ({ nativeEvent }: LayoutChangeEvent) => {
- this.setState({ rowWidth: nativeEvent.layout.width });
- };
-
- private currentOffset = () => {
- const { leftWidth = 0, rowWidth = 0, rowState } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- if (rowState === 1) {
- return leftWidth;
- } else if (rowState === -1) {
- return -rightWidth;
- }
- return 0;
- };
-
- close = () => {
- this.animateRow(this.currentOffset(), 0);
- };
-
- openLeft = () => {
- const { leftWidth = 0 } = this.state;
- this.animateRow(this.currentOffset(), leftWidth);
- };
-
- openRight = () => {
- const { rowWidth = 0 } = this.state;
- const { rightOffset = rowWidth } = this.state;
- const rightWidth = rowWidth - rightOffset;
- this.animateRow(this.currentOffset(), -rightWidth);
- };
-
- reset = () => {
- const { dragX, rowTranslation } = this.state;
- dragX.setValue(0);
- rowTranslation.setValue(0);
- this.setState({ rowState: 0 });
- };
-
- render() {
- const { rowState } = this.state;
- const {
- children,
- renderLeftActions,
- renderRightActions,
- dragOffsetFromLeftEdge = 10,
- dragOffsetFromRightEdge = 10,
- } = this.props;
-
- const left = renderLeftActions && (
-
- {renderLeftActions(this.showLeftAction!, this.transX!, this)}
-
- this.setState({ leftWidth: nativeEvent.layout.x })
- }
- />
-
- );
-
- const right = renderRightActions && (
-
- {renderRightActions(this.showRightAction!, this.transX!, this)}
-
- this.setState({ rightOffset: nativeEvent.layout.x })
- }
- />
-
- );
-
- return (
-
-
- {left}
- {right}
-
-
- {children}
-
-
-
-
- );
- }
-}
-
-const styles = StyleSheet.create({
- container: {
- overflow: 'hidden',
- },
- leftActions: {
- ...StyleSheet.absoluteFillObject,
- flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
- },
- rightActions: {
- ...StyleSheet.absoluteFillObject,
- flexDirection: I18nManager.isRTL ? 'row' : 'row-reverse',
- },
-});
diff --git a/src/handlers/gestures/GestureDetector/utils.ts b/src/handlers/gestures/GestureDetector/utils.ts
index 3d3d79ed70..12f8a19828 100644
--- a/src/handlers/gestures/GestureDetector/utils.ts
+++ b/src/handlers/gestures/GestureDetector/utils.ts
@@ -17,7 +17,6 @@ import {
HandlerStateChangeEvent,
baseGestureHandlerWithDetectorProps,
} from '../../gestureHandlerCommon';
-import { isNewWebImplementationEnabled } from '../../../EnableNewWebImplementation';
import { getReactNativeVersion } from '../../../getReactNativeVersion';
import { RNRenderer } from '../../../RNRenderer';
import { useCallback, useRef, useState } from 'react';
@@ -176,10 +175,8 @@ export function useWebEventHandlers() {
onGestureHandlerEvent: (e: HandlerStateChangeEvent) => {
onGestureHandlerEvent(e.nativeEvent);
},
- onGestureHandlerStateChange: isNewWebImplementationEnabled()
- ? (e: HandlerStateChangeEvent) => {
- onGestureHandlerEvent(e.nativeEvent);
- }
- : undefined,
+ onGestureHandlerStateChange: (e: HandlerStateChangeEvent) => {
+ onGestureHandlerEvent(e.nativeEvent);
+ },
});
}
diff --git a/src/index.ts b/src/index.ts
index d636ad1a7a..89b61d13f6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -142,24 +142,7 @@ export type {
BorderlessButtonProperties,
} from './handlers/gestureHandlerTypesCompat';
-export type { SwipeableProps } from './components/Swipeable';
-export { default as Swipeable } from './components/Swipeable';
export type { PressableProps } from './components/Pressable';
export { default as Pressable } from './components/Pressable';
-export type {
- DrawerLayoutProps,
- DrawerPosition,
- DrawerState,
- DrawerType,
- DrawerLockMode,
- DrawerKeyboardDismissMode,
-} from './components/DrawerLayout';
-export { default as DrawerLayout } from './components/DrawerLayout';
-
-export {
- enableExperimentalWebImplementation,
- enableLegacyWebImplementation,
-} from './EnableNewWebImplementation';
-
initialize();
diff --git a/src/web/Gestures.ts b/src/web/Gestures.ts
index 279b1152d1..fb57ba2f90 100644
--- a/src/web/Gestures.ts
+++ b/src/web/Gestures.ts
@@ -9,15 +9,6 @@ import NativeViewGestureHandler from './handlers/NativeViewGestureHandler';
import ManualGestureHandler from './handlers/ManualGestureHandler';
import HoverGestureHandler from './handlers/HoverGestureHandler';
-// Hammer Handlers
-import HammerNativeViewGestureHandler from '../web_hammer/NativeViewGestureHandler';
-import HammerPanGestureHandler from '../web_hammer/PanGestureHandler';
-import HammerTapGestureHandler from '../web_hammer/TapGestureHandler';
-import HammerLongPressGestureHandler from '../web_hammer/LongPressGestureHandler';
-import HammerPinchGestureHandler from '../web_hammer/PinchGestureHandler';
-import HammerRotationGestureHandler from '../web_hammer/RotationGestureHandler';
-import HammerFlingGestureHandler from '../web_hammer/FlingGestureHandler';
-
export const Gestures = {
NativeViewGestureHandler,
PanGestureHandler,
@@ -29,13 +20,3 @@ export const Gestures = {
ManualGestureHandler,
HoverGestureHandler,
};
-
-export const HammerGestures = {
- NativeViewGestureHandler: HammerNativeViewGestureHandler,
- PanGestureHandler: HammerPanGestureHandler,
- TapGestureHandler: HammerTapGestureHandler,
- LongPressGestureHandler: HammerLongPressGestureHandler,
- PinchGestureHandler: HammerPinchGestureHandler,
- RotationGestureHandler: HammerRotationGestureHandler,
- FlingGestureHandler: HammerFlingGestureHandler,
-};
diff --git a/src/web_hammer/DiscreteGestureHandler.ts b/src/web_hammer/DiscreteGestureHandler.ts
deleted file mode 100644
index cd2b603b88..0000000000
--- a/src/web_hammer/DiscreteGestureHandler.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-/* eslint-disable eslint-comments/no-unlimited-disable */
-/* eslint-disable */
-import GestureHandler from './GestureHandler';
-import { TEST_MAX_IF_NOT_NAN } from './utils';
-
-abstract class DiscreteGestureHandler extends GestureHandler {
- get isDiscrete() {
- return true;
- }
-
- get shouldEnableGestureOnSetup() {
- return true;
- }
-
- shouldFailUnderCustomCriteria(
- { x, y, deltaX, deltaY }: any,
- { maxDeltaX, maxDeltaY, maxDistSq, shouldCancelWhenOutside }: any
- ) {
- if (shouldCancelWhenOutside) {
- if (!this.isPointInView({ x, y })) {
- return true;
- }
- }
- return (
- TEST_MAX_IF_NOT_NAN(Math.abs(deltaX), maxDeltaX) ||
- TEST_MAX_IF_NOT_NAN(Math.abs(deltaY), maxDeltaY) ||
- TEST_MAX_IF_NOT_NAN(
- Math.abs(deltaY * deltaY + deltaX * deltaX),
- maxDistSq
- )
- );
- }
-
- transformNativeEvent({ center: { x, y } }: any) {
- // @ts-ignore FIXME(TS)
- const rect = this.view!.getBoundingClientRect();
-
- return {
- absoluteX: x,
- absoluteY: y,
- x: x - rect.left,
- y: y - rect.top,
- };
- }
-
- isGestureEnabledForEvent(
- {
- minPointers,
- maxPointers,
- maxDeltaX,
- maxDeltaY,
- maxDistSq,
- shouldCancelWhenOutside,
- }: any,
- _recognizer: any,
- { maxPointers: pointerLength, center, deltaX, deltaY }: any
- ) {
- const validPointerCount =
- pointerLength >= minPointers && pointerLength <= maxPointers;
-
- if (
- this.shouldFailUnderCustomCriteria(
- { ...center, deltaX, deltaY },
- {
- maxDeltaX,
- maxDeltaY,
- maxDistSq,
- shouldCancelWhenOutside,
- }
- ) ||
- // A user probably won't land a multi-pointer tap on the first tick (so we cannot just cancel each time)
- // but if the gesture is running and the user adds or subtracts another pointer then it should fail.
- (!validPointerCount && this.isGestureRunning)
- ) {
- return { failed: true };
- }
-
- return { success: validPointerCount };
- }
-}
-
-export default DiscreteGestureHandler;
diff --git a/src/web_hammer/DraggingGestureHandler.ts b/src/web_hammer/DraggingGestureHandler.ts
deleted file mode 100644
index e93e3c6b1e..0000000000
--- a/src/web_hammer/DraggingGestureHandler.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-/* eslint-disable eslint-comments/no-unlimited-disable */
-/* eslint-disable */
-import GestureHandler, { HammerInputExt } from './GestureHandler';
-import { PixelRatio } from 'react-native';
-
-abstract class DraggingGestureHandler extends GestureHandler {
- get shouldEnableGestureOnSetup() {
- return true;
- }
-
- transformNativeEvent({
- deltaX,
- deltaY,
- velocityX,
- velocityY,
- center: { x, y },
- }: HammerInputExt) {
- // @ts-ignore FIXME(TS)
- const rect = this.view!.getBoundingClientRect();
- const ratio = PixelRatio.get();
- return {
- translationX: deltaX - (this.__initialX || 0),
- translationY: deltaY - (this.__initialY || 0),
- absoluteX: x,
- absoluteY: y,
- velocityX: velocityX * ratio,
- velocityY: velocityY * ratio,
- x: x - rect.left,
- y: y - rect.top,
- };
- }
-}
-
-export default DraggingGestureHandler;
diff --git a/src/web_hammer/Errors.ts b/src/web_hammer/Errors.ts
deleted file mode 100644
index a0e1a52a98..0000000000
--- a/src/web_hammer/Errors.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export class GesturePropError extends Error {
- constructor(name: string, value: unknown, expectedType: string) {
- super(
- `Invalid property \`${name}: ${value}\` expected \`${expectedType}\``
- );
- }
-}
diff --git a/src/web_hammer/FlingGestureHandler.ts b/src/web_hammer/FlingGestureHandler.ts
deleted file mode 100644
index e3582009ed..0000000000
--- a/src/web_hammer/FlingGestureHandler.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-/* eslint-disable eslint-comments/no-unlimited-disable */
-/* eslint-disable */
-import Hammer from '@egjs/hammerjs';
-
-import { Direction } from './constants';
-import { GesturePropError } from './Errors';
-import DraggingGestureHandler from './DraggingGestureHandler';
-import { isnan } from './utils';
-import { HammerInputExt } from './GestureHandler';
-
-class FlingGestureHandler extends DraggingGestureHandler {
- get name() {
- return 'swipe';
- }
-
- get NativeGestureClass() {
- return Hammer.Swipe;
- }
-
- onGestureActivated(event: HammerInputExt) {
- this.sendEvent({
- ...event,
- eventType: Hammer.INPUT_MOVE,
- isFinal: false,
- isFirst: true,
- });
- this.isGestureRunning = false;
- this.hasGestureFailed = false;
- this.sendEvent({
- ...event,
- eventType: Hammer.INPUT_END,
- isFinal: true,
- });
- }
-
- onRawEvent(ev: HammerInputExt) {
- super.onRawEvent(ev);
- if (this.hasGestureFailed) {
- return;
- }
- // Hammer doesn't send a `cancel` event for taps.
- // Manually fail the event.
- if (ev.isFinal) {
- setTimeout(() => {
- if (this.isGestureRunning) {
- this.cancelEvent(ev);
- }
- });
- } else if (!this.hasGestureFailed && !this.isGestureRunning) {
- // Tap Gesture start event
- const gesture = this.hammer!.get(this.name);
- // @ts-ignore FIXME(TS)
- if (gesture.options.enable(gesture, ev)) {
- this.onStart(ev);
- this.sendEvent(ev);
- }
- }
- }
-
- getHammerConfig() {
- return {
- // @ts-ignore FIXME(TS)
- pointers: this.config.numberOfPointers,
- direction: this.getDirection(),
- };
- }
-
- getTargetDirections(direction: number) {
- const directions = [];
- if (direction & Direction.RIGHT) {
- directions.push(Hammer.DIRECTION_RIGHT);
- }
- if (direction & Direction.LEFT) {
- directions.push(Hammer.DIRECTION_LEFT);
- }
- if (direction & Direction.UP) {
- directions.push(Hammer.DIRECTION_UP);
- }
- if (direction & Direction.DOWN) {
- directions.push(Hammer.DIRECTION_DOWN);
- }
- // const hammerDirection = directions.reduce((a, b) => a | b, 0);
- return directions;
- }
-
- getDirection() {
- // @ts-ignore FIXME(TS)
- const { direction } = this.getConfig();
-
- let directions = [];
- if (direction & Direction.RIGHT) {
- directions.push(Hammer.DIRECTION_HORIZONTAL);
- }
- if (direction & Direction.LEFT) {
- directions.push(Hammer.DIRECTION_HORIZONTAL);
- }
- if (direction & Direction.UP) {
- directions.push(Hammer.DIRECTION_VERTICAL);
- }
- if (direction & Direction.DOWN) {
- directions.push(Hammer.DIRECTION_VERTICAL);
- }
- directions = [...new Set(directions)];
-
- if (directions.length === 0) return Hammer.DIRECTION_NONE;
- if (directions.length === 1) return directions[0];
- return Hammer.DIRECTION_ALL;
- }
-
- isGestureEnabledForEvent(
- { numberOfPointers }: any,
- _recognizer: any,
- { maxPointers: pointerLength }: any
- ) {
- const validPointerCount = pointerLength === numberOfPointers;
- if (!validPointerCount && this.isGestureRunning) {
- return { failed: true };
- }
- return { success: validPointerCount };
- }
-
- updateGestureConfig({ numberOfPointers = 1, direction, ...props }: any) {
- if (isnan(direction) || typeof direction !== 'number') {
- throw new GesturePropError('direction', direction, 'number');
- }
- return super.updateGestureConfig({
- numberOfPointers,
- direction,
- ...props,
- });
- }
-}
-
-export default FlingGestureHandler;
diff --git a/src/web_hammer/GestureHandler.ts b/src/web_hammer/GestureHandler.ts
deleted file mode 100644
index 4ff297fffd..0000000000
--- a/src/web_hammer/GestureHandler.ts
+++ /dev/null
@@ -1,599 +0,0 @@
-/* eslint-disable eslint-comments/no-unlimited-disable */
-/* eslint-disable */
-import Hammer from '@egjs/hammerjs';
-import { findNodeHandle } from 'react-native';
-
-import { State } from '../State';
-import { EventMap } from './constants';
-import * as NodeManager from './NodeManager';
-import { ghQueueMicrotask } from '../ghQueueMicrotask';
-
-// TODO(TS) Replace with HammerInput if https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50438/files is merged
-export type HammerInputExt = Omit;
-
-export type Config = Partial<{
- enabled: boolean;
- minPointers: number;
- maxPointers: number;
- minDist: number;
- minDistSq: number;
- minVelocity: number;
- minVelocitySq: number;
- maxDist: number;
- maxDistSq: number;
- failOffsetXStart: number;
- failOffsetYStart: number;
- failOffsetXEnd: number;
- failOffsetYEnd: number;
- activeOffsetXStart: number;
- activeOffsetXEnd: number;
- activeOffsetYStart: number;
- activeOffsetYEnd: number;
- waitFor: any[] | null;
- simultaneousHandlers: any[] | null;
-}>;
-
-type NativeEvent = ReturnType;
-
-let gestureInstances = 0;
-
-abstract class GestureHandler {
- public handlerTag: any;
- public isGestureRunning = false;
- public view: number | null = null;
- protected hasCustomActivationCriteria: boolean;
- protected hasGestureFailed = false;
- protected hammer: HammerManager | null = null;
- protected initialRotation: number | null = null;
- protected __initialX: any;
- protected __initialY: any;
- protected config: Config = {};
- protected previousState: State = State.UNDETERMINED;
- private pendingGestures: Record = {};
- private oldState: State = State.UNDETERMINED;
- private lastSentState: State | null = null;
- private gestureInstance: number;
- private _stillWaiting: any;
- private propsRef: any;
- private ref: any;
-
- abstract get name(): string;
-
- get id() {
- return `${this.name}${this.gestureInstance}`;
- }
-
- // a simple way to check if GestureHandler is NativeViewGestureHandler, since importing it
- // here to use instanceof would cause import cycle
- get isNative() {
- return false;
- }
-
- get isDiscrete() {
- return false;
- }
-
- get shouldEnableGestureOnSetup(): boolean {
- throw new Error('Must override GestureHandler.shouldEnableGestureOnSetup');
- }
-
- constructor() {
- this.gestureInstance = gestureInstances++;
- this.hasCustomActivationCriteria = false;
- }
-
- getConfig() {
- return this.config;
- }
-
- onWaitingEnded(_gesture: this) {}
-
- removePendingGesture(id: string) {
- delete this.pendingGestures[id];
- }
-
- addPendingGesture(gesture: this) {
- this.pendingGestures[gesture.id] = gesture;
- }
-
- isGestureEnabledForEvent(
- _config: any,
- _recognizer: any,
- _event: any
- ): { failed?: boolean; success?: boolean } {
- return { success: true };
- }
-
- get NativeGestureClass(): RecognizerStatic {
- throw new Error('Must override GestureHandler.NativeGestureClass');
- }
-
- updateHasCustomActivationCriteria(_config: Config) {
- return true;
- }
-
- clearSelfAsPending = () => {
- if (Array.isArray(this.config.waitFor)) {
- for (const gesture of this.config.waitFor) {
- gesture.removePendingGesture(this.id);
- }
- }
- };
-
- updateGestureConfig({ enabled = true, ...props }) {
- this.clearSelfAsPending();
-
- this.config = this.ensureConfig({ enabled, ...props });
- this.hasCustomActivationCriteria = this.updateHasCustomActivationCriteria(
- this.config
- );
- if (Array.isArray(this.config.waitFor)) {
- for (const gesture of this.config.waitFor) {
- gesture.addPendingGesture(this);
- }
- }
-
- if (this.hammer) {
- this.sync();
- }
- return this.config;
- }
-
- destroy = () => {
- this.clearSelfAsPending();
-
- if (this.hammer) {
- this.hammer.stop(false);
- this.hammer.destroy();
- }
- this.hammer = null;
- };
-
- isPointInView = ({ x, y }: { x: number; y: number }) => {
- // @ts-ignore FIXME(TS)
- const rect = this.view!.getBoundingClientRect();
- const pointerInside =
- x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
- return pointerInside;
- };
-
- getState(type: keyof typeof EventMap): State {
- // @ts-ignore TODO(TS) check if this is needed
- if (type == 0) {
- return 0;
- }
- return EventMap[type];
- }
-
- transformEventData(event: HammerInputExt) {
- const { eventType, maxPointers: numberOfPointers } = event;
- // const direction = DirectionMap[ev.direction];
- const changedTouch = event.changedPointers[0];
- const pointerInside = this.isPointInView({
- x: changedTouch.clientX,
- y: changedTouch.clientY,
- });
-
- // TODO(TS) Remove cast after https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50966 is merged.
- const state = this.getState(eventType as 1 | 2 | 4 | 8);
- if (state !== this.previousState) {
- this.oldState = this.previousState;
- this.previousState = state;
- }
-
- return {
- nativeEvent: {
- numberOfPointers,
- state,
- pointerInside,
- ...this.transformNativeEvent(event),
- // onHandlerStateChange only
- handlerTag: this.handlerTag,
- target: this.ref,
- // send oldState only when the state was changed, or is different than ACTIVE
- // GestureDetector relies on the presence of `oldState` to differentiate between
- // update events and state change events
- oldState:
- state !== this.previousState || state != 4
- ? this.oldState
- : undefined,
- },
- timeStamp: Date.now(),
- };
- }
-
- transformNativeEvent(_event: HammerInputExt) {
- return {};
- }
-
- sendEvent = (nativeEvent: HammerInputExt) => {
- const { onGestureHandlerEvent, onGestureHandlerStateChange } =
- this.propsRef.current;
-
- const event = this.transformEventData(nativeEvent);
-
- invokeNullableMethod(onGestureHandlerEvent, event);
- if (this.lastSentState !== event.nativeEvent.state) {
- this.lastSentState = event.nativeEvent.state as State;
- invokeNullableMethod(onGestureHandlerStateChange, event);
- }
- };
-
- cancelPendingGestures(event: HammerInputExt) {
- for (const gesture of Object.values(this.pendingGestures)) {
- if (gesture && gesture.isGestureRunning) {
- gesture.hasGestureFailed = true;
- gesture.cancelEvent(event);
- }
- }
- }
-
- notifyPendingGestures() {
- for (const gesture of Object.values(this.pendingGestures)) {
- if (gesture) {
- gesture.onWaitingEnded(this);
- }
- }
- }
-
- // FIXME event is undefined in runtime when firstly invoked (see Draggable example), check other functions taking event as input
- onGestureEnded(event: HammerInputExt) {
- this.isGestureRunning = false;
- this.cancelPendingGestures(event);
- }
-
- forceInvalidate(event: HammerInputExt) {
- if (this.isGestureRunning) {
- this.hasGestureFailed = true;
- this.cancelEvent(event);
- }
- }
-
- cancelEvent(event: HammerInputExt) {
- this.notifyPendingGestures();
- this.sendEvent({
- ...event,
- eventType: Hammer.INPUT_CANCEL,
- isFinal: true,
- });
- this.onGestureEnded(event);
- }
-
- onRawEvent({ isFirst }: HammerInputExt) {
- if (isFirst) {
- this.hasGestureFailed = false;
- }
- }
-
- shouldUseTouchEvents(config: Config) {
- return (
- config.simultaneousHandlers?.some((handler) => handler.isNative) ?? false
- );
- }
-
- setView(ref: Parameters['0'], propsRef: any) {
- if (ref == null) {
- this.destroy();
- this.view = null;
- return;
- }
-
- // @ts-ignore window doesn't exist on global type as we don't want to use Node types
- const SUPPORTS_TOUCH = 'ontouchstart' in window;
- this.propsRef = propsRef;
- this.ref = ref;
-
- this.view = findNodeHandle(ref);
-
- // When the browser starts handling the gesture (e.g. scrolling), it sends a pointercancel event and stops
- // sending additional pointer events. This is not the case with touch events, so if the gesture is simultaneous
- // with a NativeGestureHandler, we need to check if touch events are supported and use them if possible.
- this.hammer =
- SUPPORTS_TOUCH && this.shouldUseTouchEvents(this.config)
- ? new Hammer.Manager(this.view as any, {
- inputClass: Hammer.TouchInput,
- })
- : new Hammer.Manager(this.view as any);
-
- this.oldState = State.UNDETERMINED;
- this.previousState = State.UNDETERMINED;
- this.lastSentState = null;
-
- const { NativeGestureClass } = this;
- // @ts-ignore TODO(TS)
- const gesture = new NativeGestureClass(this.getHammerConfig());
- this.hammer.add(gesture);
-
- this.hammer.on('hammer.input', (ev: HammerInput) => {
- if (!this.config.enabled) {
- this.hasGestureFailed = false;
- this.isGestureRunning = false;
- return;
- }
-
- this.onRawEvent(ev as unknown as HammerInputExt);
-
- // TODO: Bacon: Check against something other than null
- // The isFirst value is not called when the first rotation is calculated.
- if (this.initialRotation === null && ev.rotation !== 0) {
- this.initialRotation = ev.rotation;
- }
- if (ev.isFinal) {
- // in favor of a willFail otherwise the last frame of the gesture will be captured.
- setTimeout(() => {
- this.initialRotation = null;
- this.hasGestureFailed = false;
- });
- }
- });
-
- this.setupEvents();
- this.sync();
- }
-
- setupEvents() {
- // TODO(TS) Hammer types aren't exactly that what we get in runtime
- if (!this.isDiscrete) {
- this.hammer!.on(`${this.name}start`, (event: HammerInput) =>
- this.onStart(event as unknown as HammerInputExt)
- );
- this.hammer!.on(
- `${this.name}end ${this.name}cancel`,
- (event: HammerInput) => {
- this.onGestureEnded(event as unknown as HammerInputExt);
- }
- );
- }
- this.hammer!.on(this.name, (ev: HammerInput) =>
- this.onGestureActivated(ev as unknown as HammerInputExt)
- ); // TODO(TS) remove cast after https://github.com/DefinitelyTyped/DefinitelyTyped/pull/50438 is merged
- }
-
- onStart({ deltaX, deltaY, rotation }: HammerInputExt) {
- // Reset the state for the next gesture
- this.oldState = State.UNDETERMINED;
- this.previousState = State.UNDETERMINED;
- this.lastSentState = null;
-
- this.isGestureRunning = true;
- this.__initialX = deltaX;
- this.__initialY = deltaY;
- this.initialRotation = rotation;
- }
-
- onGestureActivated(ev: HammerInputExt) {
- this.sendEvent(ev);
- }
-
- onSuccess() {}
-
- _getPendingGestures() {
- if (Array.isArray(this.config.waitFor) && this.config.waitFor.length) {
- // Get the list of gestures that this gesture is still waiting for.
- // Use `=== false` in case a ref that isn't a gesture handler is used.
- const stillWaiting = this.config.waitFor.filter(
- ({ hasGestureFailed }) => hasGestureFailed === false
- );
- return stillWaiting;
- }
- return [];
- }
-
- getHammerConfig() {
- const pointers =
- this.config.minPointers === this.config.maxPointers
- ? this.config.minPointers
- : 0;
- return {
- pointers,
- };
- }
-
- sync = () => {
- const gesture = this.hammer!.get(this.name);
- if (!gesture) return;
-
- const enable = (recognizer: any, inputData: any) => {
- if (!this.config.enabled) {
- this.isGestureRunning = false;
- this.hasGestureFailed = false;
- return false;
- }
-
- // Prevent events before the system is ready.
- if (
- !inputData ||
- !recognizer.options ||
- typeof inputData.maxPointers === 'undefined'
- ) {
- return this.shouldEnableGestureOnSetup;
- }
-
- if (this.hasGestureFailed) {
- return false;
- }
-
- if (!this.isDiscrete) {
- if (this.isGestureRunning) {
- return true;
- }
- // The built-in hammer.js "waitFor" doesn't work across multiple views.
- // Only process if there are views to wait for.
- this._stillWaiting = this._getPendingGestures();
- // This gesture should continue waiting.
- if (this._stillWaiting.length) {
- // Check to see if one of the gestures you're waiting for has started.
- // If it has then the gesture should fail.
- for (const gesture of this._stillWaiting) {
- // When the target gesture has started, this gesture must force fail.
- if (!gesture.isDiscrete && gesture.isGestureRunning) {
- this.hasGestureFailed = true;
- this.isGestureRunning = false;
- return false;
- }
- }
- // This gesture shouldn't start until the others have finished.
- return false;
- }
- }
-
- // Use default behaviour
- if (!this.hasCustomActivationCriteria) {
- return true;
- }
-
- const deltaRotation =
- this.initialRotation == null
- ? 0
- : inputData.rotation - this.initialRotation;
- // @ts-ignore FIXME(TS)
- const { success, failed } = this.isGestureEnabledForEvent(
- this.getConfig(),
- recognizer,
- {
- ...inputData,
- deltaRotation,
- }
- );
-
- if (failed) {
- this.simulateCancelEvent(inputData);
- this.hasGestureFailed = true;
- }
- return success;
- };
-
- const params = this.getHammerConfig();
- // @ts-ignore FIXME(TS)
- gesture.set({ ...params, enable });
- };
-
- simulateCancelEvent(_inputData: any) {}
-
- // Validate the props
- ensureConfig(config: Config): Required {
- const props = { ...config };
-
- // TODO(TS) We use ! to assert that if property is present then value is not empty (null, undefined)
- if ('minDist' in config) {
- props.minDist = config.minDist;
- props.minDistSq = props.minDist! * props.minDist!;
- }
- if ('minVelocity' in config) {
- props.minVelocity = config.minVelocity;
- props.minVelocitySq = props.minVelocity! * props.minVelocity!;
- }
- if ('maxDist' in config) {
- props.maxDist = config.maxDist;
- props.maxDistSq = config.maxDist! * config.maxDist!;
- }
- if ('waitFor' in config) {
- props.waitFor = asArray(config.waitFor)
- .map(({ handlerTag }: { handlerTag: number }) =>
- NodeManager.getHandler(handlerTag)
- )
- .filter((v) => v);
- } else {
- props.waitFor = null;
- }
- if ('simultaneousHandlers' in config) {
- const shouldUseTouchEvents = this.shouldUseTouchEvents(this.config);
- props.simultaneousHandlers = asArray(config.simultaneousHandlers)
- .map((handler: number | GestureHandler) => {
- if (typeof handler === 'number') {
- return NodeManager.getHandler(handler);
- } else {
- return NodeManager.getHandler(handler.handlerTag);
- }
- })
- .filter((v) => v);
-
- if (shouldUseTouchEvents !== this.shouldUseTouchEvents(props)) {
- ghQueueMicrotask(() => {
- // if the undelying event API needs to be changed, we need to unmount and mount
- // the hammer instance again.
- this.destroy();
- this.setView(this.ref, this.propsRef);
- });
- }
- } else {
- props.simultaneousHandlers = null;
- }
-
- const configProps = [
- 'minPointers',
- 'maxPointers',
- 'minDist',
- 'maxDist',
- 'maxDistSq',
- 'minVelocitySq',
- 'minDistSq',
- 'minVelocity',
- 'failOffsetXStart',
- 'failOffsetYStart',
- 'failOffsetXEnd',
- 'failOffsetYEnd',
- 'activeOffsetXStart',
- 'activeOffsetXEnd',
- 'activeOffsetYStart',
- 'activeOffsetYEnd',
- ] as const;
- configProps.forEach((prop: typeof configProps[number]) => {
- if (typeof props[prop] === 'undefined') {
- props[prop] = Number.NaN;
- }
- });
- return props as Required; // TODO(TS) how to convince TS that props are filled?
- }
-}
-
-// TODO(TS) investigate this method
-// Used for sending data to a callback or AnimatedEvent
-function invokeNullableMethod(
- method:
- | ((event: NativeEvent) => void)
- | { __getHandler: () => (event: NativeEvent) => void }
- | { __nodeConfig: { argMapping: any } },
- event: NativeEvent
-) {
- if (method) {
- if (typeof method === 'function') {
- method(event);
- } else {
- // For use with reanimated's AnimatedEvent
- if (
- '__getHandler' in method &&
- typeof method.__getHandler === 'function'
- ) {
- const handler = method.__getHandler();
- invokeNullableMethod(handler, event);
- } else {
- if ('__nodeConfig' in method) {
- const { argMapping } = method.__nodeConfig;
- if (Array.isArray(argMapping)) {
- for (const [index, [key, value]] of argMapping.entries()) {
- if (key in event.nativeEvent) {
- // @ts-ignore fix method type
- const nativeValue = event.nativeEvent[key];
- if (value && value.setValue) {
- // Reanimated API
- value.setValue(nativeValue);
- } else {
- // RN Animated API
- method.__nodeConfig.argMapping[index] = [key, nativeValue];
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-function asArray(value: T | T[]) {
- // TODO(TS) use config.waitFor type
- return value == null ? [] : Array.isArray(value) ? value : [value];
-}
-
-export default GestureHandler;
diff --git a/src/web_hammer/IndiscreteGestureHandler.ts b/src/web_hammer/IndiscreteGestureHandler.ts
deleted file mode 100644
index d63ba2fee8..0000000000
--- a/src/web_hammer/IndiscreteGestureHandler.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import GestureHandler from './GestureHandler';
-
-/**
- * The base class for **Rotation** and **Pinch** gesture handlers.
- */
-abstract class IndiscreteGestureHandler extends GestureHandler {
- get shouldEnableGestureOnSetup() {
- return false;
- }
-
- updateGestureConfig({ minPointers = 2, maxPointers = 2, ...props }) {
- return super.updateGestureConfig({
- minPointers,
- maxPointers,
- ...props,
- });
- }
-
- isGestureEnabledForEvent(
- { minPointers, maxPointers }: any,
- _recognizer: any,
- { maxPointers: pointerLength }: any
- ) {
- if (pointerLength > maxPointers) {
- return { failed: true };
- }
- const validPointerCount = pointerLength >= minPointers;
- return {
- success: validPointerCount,
- };
- }
-}
-export default IndiscreteGestureHandler;
diff --git a/src/web_hammer/LongPressGestureHandler.ts b/src/web_hammer/LongPressGestureHandler.ts
deleted file mode 100644
index 7dcf41a9a0..0000000000
--- a/src/web_hammer/LongPressGestureHandler.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/* eslint-disable eslint-comments/no-unlimited-disable */
-/* eslint-disable */
-import Hammer from '@egjs/hammerjs';
-
-import { State } from '../State';
-import PressGestureHandler from './PressGestureHandler';
-import { isnan, isValidNumber } from './utils';
-import { Config } from './GestureHandler';
-import { HammerInputNames } from './constants';
-
-class LongPressGestureHandler extends PressGestureHandler {
- get minDurationMs(): number {
- // @ts-ignore FIXNE(TS)
- return isnan(this.config.minDurationMs) ? 251 : this.config.minDurationMs;
- }
-
- get maxDist() {
- // @ts-ignore FIXNE(TS)
- return isnan(this.config.maxDist) ? 9 : this.config.maxDist;
- }
-
- updateHasCustomActivationCriteria({ maxDistSq }: Config) {
- return !isValidNumber(maxDistSq);
- }
-
- getConfig() {
- if (!this.hasCustomActivationCriteria) {
- // Default config
- // If no params have been defined then this config should emulate the native gesture as closely as possible.
- return {
- shouldCancelWhenOutside: true,
- maxDistSq: 10,
- };
- }
- return this.config;
- }
-
- getHammerConfig() {
- return {
- ...super.getHammerConfig(),
- // threshold: this.maxDist,
- time: this.minDurationMs,
- };
- }
-
- getState(type: keyof typeof HammerInputNames) {
- return {
- [Hammer.INPUT_START]: State.ACTIVE,
- [Hammer.INPUT_MOVE]: State.ACTIVE,
- [Hammer.INPUT_END]: State.END,
- [Hammer.INPUT_CANCEL]: State.FAILED,
- }[type];
- }
-}
-
-export default LongPressGestureHandler;
diff --git a/src/web_hammer/NativeViewGestureHandler.ts b/src/web_hammer/NativeViewGestureHandler.ts
deleted file mode 100644
index 7deb5bddc4..0000000000
--- a/src/web_hammer/NativeViewGestureHandler.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import DiscreteGestureHandler from './DiscreteGestureHandler';
-import { HammerInputExt } from './GestureHandler';
-import * as NodeManager from './NodeManager';
-import PressGestureHandler from './PressGestureHandler';
-import { TEST_MIN_IF_NOT_NAN, VEC_LEN_SQ } from './utils';
-
-class NativeViewGestureHandler extends PressGestureHandler {
- get isNative() {
- return true;
- }
-
- onRawEvent(ev: HammerInputExt) {
- super.onRawEvent(ev);
- if (!ev.isFinal) {
- // if (this.ref instanceof ScrollView) {
- if (TEST_MIN_IF_NOT_NAN(VEC_LEN_SQ({ x: ev.deltaX, y: ev.deltaY }), 10)) {
- // @ts-ignore FIXME(TS) config type
- if (this.config.disallowInterruption) {
- const gestures = Object.values(NodeManager.getNodes()).filter(
- (gesture) => {
- const { handlerTag, view, isGestureRunning } = gesture;
- return (
- // Check if this gesture isn't self
- handlerTag !== this.handlerTag &&
- // Ensure the gesture needs to be cancelled
- isGestureRunning &&
- // ScrollView can cancel discrete gestures like taps and presses
- gesture instanceof DiscreteGestureHandler &&
- // Ensure a view exists and is a child of the current view
- view &&
- // @ts-ignore FIXME(TS) view type
- this.view.contains(view)
- );
- }
- );
- // Cancel all of the gestures that passed the filter
- for (const gesture of gestures) {
- // TODO: Bacon: Send some cached event.
- gesture.forceInvalidate(ev);
- }
- }
- }
- }
- }
-}
-
-export default NativeViewGestureHandler;
diff --git a/src/web_hammer/NodeManager.ts b/src/web_hammer/NodeManager.ts
deleted file mode 100644
index f5ec70a43b..0000000000
--- a/src/web_hammer/NodeManager.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-export const gestures: Record = {};
-
-export function getHandler(tag: number) {
- if (tag in gestures) {
- return gestures[tag];
- }
-
- throw new Error(`No handler for tag ${tag}`);
-}
-
-export function createGestureHandler(handlerTag: number, handler: any) {
- if (handlerTag in gestures) {
- throw new Error(`Handler with tag ${handlerTag} already exists`);
- }
- gestures[handlerTag] = handler;
- // @ts-ignore no types for web handlers yet
- gestures[handlerTag].handlerTag = handlerTag;
-}
-
-export function dropGestureHandler(handlerTag: number) {
- // Since React 18, there are cases where componentWillUnmount gets called twice in a row
- // so skip this if the tag was already removed.
- if (!(handlerTag in gestures)) {
- return;
- }
- getHandler(handlerTag).destroy();
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
- delete gestures[handlerTag];
-}
-
-export function getNodes() {
- return { ...gestures };
-}
diff --git a/src/web_hammer/PanGestureHandler.ts b/src/web_hammer/PanGestureHandler.ts
deleted file mode 100644
index 4a7e17da88..0000000000
--- a/src/web_hammer/PanGestureHandler.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-
-import {
- EventMap,
- MULTI_FINGER_PAN_MAX_PINCH_THRESHOLD,
- MULTI_FINGER_PAN_MAX_ROTATION_THRESHOLD,
-} from './constants';
-import DraggingGestureHandler from './DraggingGestureHandler';
-import { isValidNumber, isnan, TEST_MIN_IF_NOT_NAN, VEC_LEN_SQ } from './utils';
-import { State } from '../State';
-
-import { Config, HammerInputExt } from './GestureHandler';
-class PanGestureHandler extends DraggingGestureHandler {
- get name() {
- return 'pan';
- }
-
- get NativeGestureClass() {
- return Hammer.Pan;
- }
-
- getHammerConfig() {
- return {
- ...super.getHammerConfig(),
- direction: this.getDirection(),
- };
- }
-
- getState(type: keyof typeof EventMap) {
- const nextState = super.getState(type);
- // Ensure that the first state sent is `BEGAN` and not `ACTIVE`
- if (
- this.previousState === State.UNDETERMINED &&
- nextState === State.ACTIVE
- ) {
- return State.BEGAN;
- }
- return nextState;
- }
-
- getDirection() {
- const config = this.getConfig();
- const {
- activeOffsetXStart,
- activeOffsetXEnd,
- activeOffsetYStart,
- activeOffsetYEnd,
- minDist,
- } = config;
- let directions: number[] = [];
- let horizontalDirections = [];
-
- if (!isnan(minDist)) {
- return Hammer.DIRECTION_ALL;
- }
-
- if (!isnan(activeOffsetXStart)) {
- horizontalDirections.push(Hammer.DIRECTION_LEFT);
- }
- if (!isnan(activeOffsetXEnd)) {
- horizontalDirections.push(Hammer.DIRECTION_RIGHT);
- }
- if (horizontalDirections.length === 2) {
- horizontalDirections = [Hammer.DIRECTION_HORIZONTAL];
- }
-
- directions = directions.concat(horizontalDirections);
- let verticalDirections = [];
-
- if (!isnan(activeOffsetYStart)) {
- verticalDirections.push(Hammer.DIRECTION_UP);
- }
- if (!isnan(activeOffsetYEnd)) {
- verticalDirections.push(Hammer.DIRECTION_DOWN);
- }
-
- if (verticalDirections.length === 2) {
- verticalDirections = [Hammer.DIRECTION_VERTICAL];
- }
-
- directions = directions.concat(verticalDirections);
-
- if (!directions.length) {
- return Hammer.DIRECTION_NONE;
- }
- if (
- directions[0] === Hammer.DIRECTION_HORIZONTAL &&
- directions[1] === Hammer.DIRECTION_VERTICAL
- ) {
- return Hammer.DIRECTION_ALL;
- }
- if (horizontalDirections.length && verticalDirections.length) {
- return Hammer.DIRECTION_ALL;
- }
-
- return directions[0];
- }
-
- getConfig() {
- if (!this.hasCustomActivationCriteria) {
- // Default config
- // If no params have been defined then this config should emulate the native gesture as closely as possible.
- return {
- minDistSq: 10,
- };
- }
- return this.config;
- }
-
- shouldFailUnderCustomCriteria(
- { deltaX, deltaY }: HammerInputExt,
- criteria: any
- ) {
- return (
- (!isnan(criteria.failOffsetXStart) &&
- deltaX < criteria.failOffsetXStart) ||
- (!isnan(criteria.failOffsetXEnd) && deltaX > criteria.failOffsetXEnd) ||
- (!isnan(criteria.failOffsetYStart) &&
- deltaY < criteria.failOffsetYStart) ||
- (!isnan(criteria.failOffsetYEnd) && deltaY > criteria.failOffsetYEnd)
- );
- }
-
- shouldActivateUnderCustomCriteria(
- { deltaX, deltaY, velocity }: any,
- criteria: any
- ) {
- return (
- (!isnan(criteria.activeOffsetXStart) &&
- deltaX < criteria.activeOffsetXStart) ||
- (!isnan(criteria.activeOffsetXEnd) &&
- deltaX > criteria.activeOffsetXEnd) ||
- (!isnan(criteria.activeOffsetYStart) &&
- deltaY < criteria.activeOffsetYStart) ||
- (!isnan(criteria.activeOffsetYEnd) &&
- deltaY > criteria.activeOffsetYEnd) ||
- TEST_MIN_IF_NOT_NAN(
- VEC_LEN_SQ({ x: deltaX, y: deltaY }),
- criteria.minDistSq
- ) ||
- TEST_MIN_IF_NOT_NAN(velocity.x, criteria.minVelocityX) ||
- TEST_MIN_IF_NOT_NAN(velocity.y, criteria.minVelocityY) ||
- TEST_MIN_IF_NOT_NAN(VEC_LEN_SQ(velocity), criteria.minVelocitySq)
- );
- }
-
- shouldMultiFingerPanFail({
- pointerLength,
- scale,
- deltaRotation,
- }: {
- deltaRotation: number;
- pointerLength: number;
- scale: number;
- }) {
- if (pointerLength <= 1) {
- return false;
- }
-
- // Test if the pan had too much pinching or rotating.
- const deltaScale = Math.abs(scale - 1);
- const absDeltaRotation = Math.abs(deltaRotation);
- if (deltaScale > MULTI_FINGER_PAN_MAX_PINCH_THRESHOLD) {
- // > If the threshold doesn't seem right.
- // You can log the value which it failed at here:
- return true;
- }
- if (absDeltaRotation > MULTI_FINGER_PAN_MAX_ROTATION_THRESHOLD) {
- // > If the threshold doesn't seem right.
- // You can log the value which it failed at here:
- return true;
- }
-
- return false;
- }
-
- updateHasCustomActivationCriteria(
- criteria: Config & { minVelocityX?: number; minVelocityY?: number }
- ) {
- return (
- isValidNumber(criteria.minDistSq) ||
- isValidNumber(criteria.minVelocityX) ||
- isValidNumber(criteria.minVelocityY) ||
- isValidNumber(criteria.minVelocitySq) ||
- isValidNumber(criteria.activeOffsetXStart) ||
- isValidNumber(criteria.activeOffsetXEnd) ||
- isValidNumber(criteria.activeOffsetYStart) ||
- isValidNumber(criteria.activeOffsetYEnd)
- );
- }
-
- isGestureEnabledForEvent(
- props: any,
- _recognizer: any,
- inputData: HammerInputExt & { deltaRotation: number }
- ) {
- if (this.shouldFailUnderCustomCriteria(inputData, props)) {
- return { failed: true };
- }
-
- const velocity = { x: inputData.velocityX, y: inputData.velocityY };
- if (
- this.hasCustomActivationCriteria &&
- this.shouldActivateUnderCustomCriteria(
- { deltaX: inputData.deltaX, deltaY: inputData.deltaY, velocity },
- props
- )
- ) {
- if (
- this.shouldMultiFingerPanFail({
- pointerLength: inputData.maxPointers,
- scale: inputData.scale,
- deltaRotation: inputData.deltaRotation,
- })
- ) {
- return {
- failed: true,
- };
- }
- return { success: true };
- }
- return { success: false };
- }
-}
-
-export default PanGestureHandler;
diff --git a/src/web_hammer/PinchGestureHandler.ts b/src/web_hammer/PinchGestureHandler.ts
deleted file mode 100644
index 3adf5b9bd1..0000000000
--- a/src/web_hammer/PinchGestureHandler.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-import { HammerInputExt } from './GestureHandler';
-
-import IndiscreteGestureHandler from './IndiscreteGestureHandler';
-
-class PinchGestureHandler extends IndiscreteGestureHandler {
- get name() {
- return 'pinch';
- }
-
- get NativeGestureClass() {
- return Hammer.Pinch;
- }
-
- transformNativeEvent({ scale, velocity, center }: HammerInputExt) {
- return {
- focalX: center.x,
- focalY: center.y,
- velocity,
- scale,
- };
- }
-}
-
-export default PinchGestureHandler;
diff --git a/src/web_hammer/PressGestureHandler.ts b/src/web_hammer/PressGestureHandler.ts
deleted file mode 100644
index 3852ed6554..0000000000
--- a/src/web_hammer/PressGestureHandler.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-
-import { State } from '../State';
-import {
- CONTENT_TOUCHES_DELAY,
- CONTENT_TOUCHES_QUICK_TAP_END_DELAY,
- HammerInputNames,
-} from './constants';
-import DiscreteGestureHandler from './DiscreteGestureHandler';
-import { Config, HammerInputExt } from './GestureHandler';
-import { fireAfterInterval, isValidNumber, isnan } from './utils';
-
-class PressGestureHandler extends DiscreteGestureHandler {
- private visualFeedbackTimer: any;
- private initialEvent: HammerInputExt | null = null;
- get name() {
- return 'press';
- }
-
- get minDurationMs() {
- // @ts-ignore FIXME(TS)
- return isnan(this.config.minDurationMs) ? 5 : this.config.minDurationMs;
- }
-
- get maxDist() {
- return isnan(this.config.maxDist) ? 9 : this.config.maxDist;
- }
-
- get NativeGestureClass() {
- return Hammer.Press;
- }
-
- shouldDelayTouches = true;
-
- simulateCancelEvent(inputData: HammerInputExt) {
- // Long press never starts so we can't rely on the running event boolean.
- this.hasGestureFailed = true;
- this.cancelEvent(inputData);
- }
-
- updateHasCustomActivationCriteria({
- shouldCancelWhenOutside,
- maxDistSq,
- }: Config & { shouldCancelWhenOutside: boolean }) {
- return shouldCancelWhenOutside || !isValidNumber(maxDistSq);
- }
-
- getState(type: keyof typeof HammerInputNames): State {
- return {
- [Hammer.INPUT_START]: State.BEGAN,
- [Hammer.INPUT_MOVE]: State.ACTIVE,
- [Hammer.INPUT_END]: State.END,
- [Hammer.INPUT_CANCEL]: State.CANCELLED,
- }[type];
- }
-
- getConfig() {
- if (!this.hasCustomActivationCriteria) {
- // Default config
- // If no params have been defined then this config should emulate the native gesture as closely as possible.
- return {
- shouldCancelWhenOutside: true,
- maxDistSq: 10,
- };
- }
- return this.config;
- }
-
- getHammerConfig() {
- return {
- ...super.getHammerConfig(),
- // threshold: this.maxDist,
- time: this.minDurationMs,
- };
- }
-
- onGestureActivated(ev: HammerInputExt) {
- this.onGestureStart(ev);
- }
-
- shouldDelayTouchForEvent({ pointerType }: HammerInputExt) {
- // Don't disable event for mouse input
- return this.shouldDelayTouches && pointerType === 'touch';
- }
-
- onGestureStart(ev: HammerInputExt) {
- this.isGestureRunning = true;
- clearTimeout(this.visualFeedbackTimer);
- this.initialEvent = ev;
- this.visualFeedbackTimer = fireAfterInterval(() => {
- this.sendGestureStartedEvent(this.initialEvent as HammerInputExt);
- this.initialEvent = null;
- }, this.shouldDelayTouchForEvent(ev) && CONTENT_TOUCHES_DELAY);
- }
-
- sendGestureStartedEvent(ev: HammerInputExt) {
- clearTimeout(this.visualFeedbackTimer);
- this.visualFeedbackTimer = null;
- this.sendEvent({
- ...ev,
- eventType: Hammer.INPUT_MOVE,
- isFirst: true,
- });
- }
-
- forceInvalidate(event: HammerInputExt) {
- super.forceInvalidate(event);
- clearTimeout(this.visualFeedbackTimer);
- this.visualFeedbackTimer = null;
- this.initialEvent = null;
- }
-
- onRawEvent(ev: HammerInputExt) {
- super.onRawEvent(ev);
- if (this.isGestureRunning) {
- if (ev.isFinal) {
- let timeout;
- if (this.visualFeedbackTimer) {
- // Aesthetic timing for a quick tap.
- // We haven't activated the tap right away to emulate iOS `delaysContentTouches`
- // Now we must send the initial activation event and wait a set amount of time before firing the end event.
- timeout = CONTENT_TOUCHES_QUICK_TAP_END_DELAY;
- this.sendGestureStartedEvent(this.initialEvent as HammerInputExt);
- this.initialEvent = null;
- }
- fireAfterInterval(() => {
- this.sendEvent({
- ...ev,
- eventType: Hammer.INPUT_END,
- isFinal: true,
- });
- // @ts-ignore -- this should explicitly support undefined
- this.onGestureEnded();
- }, timeout);
- } else {
- this.sendEvent({
- ...ev,
- eventType: Hammer.INPUT_MOVE,
- isFinal: false,
- });
- }
- }
- }
-
- updateGestureConfig({
- shouldActivateOnStart = false,
- disallowInterruption = false,
- shouldCancelWhenOutside = true,
- minDurationMs = Number.NaN,
- maxDist = Number.NaN,
- minPointers = 1,
- maxPointers = 1,
- ...props
- }) {
- return super.updateGestureConfig({
- shouldActivateOnStart,
- disallowInterruption,
- shouldCancelWhenOutside,
- minDurationMs,
- maxDist,
- minPointers,
- maxPointers,
- ...props,
- });
- }
-}
-export default PressGestureHandler;
diff --git a/src/web_hammer/RotationGestureHandler.ts b/src/web_hammer/RotationGestureHandler.ts
deleted file mode 100644
index c1404366a0..0000000000
--- a/src/web_hammer/RotationGestureHandler.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-
-import { DEG_RAD } from './constants';
-import { HammerInputExt } from './GestureHandler';
-import IndiscreteGestureHandler from './IndiscreteGestureHandler';
-
-class RotationGestureHandler extends IndiscreteGestureHandler {
- get name() {
- return 'rotate';
- }
-
- get NativeGestureClass() {
- return Hammer.Rotate;
- }
-
- transformNativeEvent({ rotation, velocity, center }: HammerInputExt) {
- return {
- rotation: (rotation - (this.initialRotation ?? 0)) * DEG_RAD,
- anchorX: center.x,
- anchorY: center.y,
- velocity,
- };
- }
-}
-export default RotationGestureHandler;
diff --git a/src/web_hammer/TapGestureHandler.ts b/src/web_hammer/TapGestureHandler.ts
deleted file mode 100644
index 312049c95e..0000000000
--- a/src/web_hammer/TapGestureHandler.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-
-import DiscreteGestureHandler from './DiscreteGestureHandler';
-import { HammerInputExt } from './GestureHandler';
-import { isnan } from './utils';
-
-class TapGestureHandler extends DiscreteGestureHandler {
- private _shouldFireEndEvent: HammerInputExt | null = null;
- private _timer: any;
- private _multiTapTimer: any; // TODO unused?
- get name() {
- return 'tap';
- }
-
- get NativeGestureClass() {
- return Hammer.Tap;
- }
-
- get maxDelayMs() {
- // @ts-ignore TODO(TS) trace down config
- return isnan(this.config.maxDelayMs) ? 300 : this.config.maxDelayMs;
- }
-
- simulateCancelEvent(inputData: HammerInputExt) {
- if (this.isGestureRunning) {
- this.cancelEvent(inputData);
- }
- }
-
- onGestureActivated(ev: HammerInputExt) {
- if (this.isGestureRunning) {
- this.onSuccessfulTap(ev);
- }
- }
-
- onSuccessfulTap = (ev: HammerInputExt) => {
- if (this._getPendingGestures().length) {
- this._shouldFireEndEvent = ev;
- return;
- }
- if (ev.eventType === Hammer.INPUT_END) {
- this.sendEvent({ ...ev, eventType: Hammer.INPUT_MOVE });
- }
- // When handler gets activated it will turn into State.END immediately.
- this.sendEvent({ ...ev, isFinal: true });
- this.onGestureEnded(ev);
- };
-
- onRawEvent(ev: HammerInput) {
- super.onRawEvent(ev);
-
- // Attempt to create a touch-down event by checking if a valid tap hasn't started yet, then validating the input.
- if (
- !this.hasGestureFailed &&
- !this.isGestureRunning &&
- // Prevent multi-pointer events from misfiring.
- !ev.isFinal
- ) {
- // Tap Gesture start event
- const gesture = this.hammer!.get(this.name);
- // @ts-ignore TODO(TS) trace down config
- if (gesture.options.enable(gesture, ev)) {
- clearTimeout(this._multiTapTimer);
-
- this.onStart(ev);
- this.sendEvent(ev);
- }
- }
- if (ev.isFinal && ev.maxPointers > 1) {
- setTimeout(() => {
- // Handle case where one finger presses slightly
- // after the first finger on a multi-tap event
- if (this.isGestureRunning) {
- this.cancelEvent(ev);
- }
- });
- }
-
- if (this.hasGestureFailed) {
- return;
- }
- // Hammer doesn't send a `cancel` event for taps.
- // Manually fail the event.
- if (ev.isFinal) {
- // Handle case where one finger presses slightly
- // after the first finger on a multi-tap event
- if (ev.maxPointers > 1) {
- setTimeout(() => {
- if (this.isGestureRunning) {
- this.cancelEvent(ev);
- }
- });
- }
-
- // Clear last timer
- clearTimeout(this._timer);
- // Create time out for multi-taps.
- this._timer = setTimeout(() => {
- this.hasGestureFailed = true;
- this.cancelEvent(ev);
- }, this.maxDelayMs);
- } else if (!this.hasGestureFailed && !this.isGestureRunning) {
- // Tap Gesture start event
- const gesture = this.hammer!.get(this.name);
- // @ts-ignore TODO(TS) trace down config
- if (gesture.options.enable(gesture, ev)) {
- clearTimeout(this._multiTapTimer);
-
- this.onStart(ev);
- this.sendEvent(ev);
- }
- }
- }
-
- getHammerConfig() {
- return {
- ...super.getHammerConfig(),
- event: this.name,
- // @ts-ignore TODO(TS) trace down config
- taps: isnan(this.config.numberOfTaps) ? 1 : this.config.numberOfTaps,
- interval: this.maxDelayMs,
- time:
- // @ts-ignore TODO(TS) trace down config
- isnan(this.config.maxDurationMs) || this.config.maxDurationMs == null
- ? 250
- : // @ts-ignore TODO(TS) trace down config
- this.config.maxDurationMs,
- };
- }
-
- updateGestureConfig({
- shouldCancelWhenOutside = true,
- maxDeltaX = Number.NaN,
- maxDeltaY = Number.NaN,
- numberOfTaps = 1,
- minDurationMs = 525,
- maxDelayMs = Number.NaN,
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- TODO possibly forgotten to use in updateGestureConfig?
- maxDurationMs = Number.NaN,
- maxDist = 2,
- minPointers = 1,
- maxPointers = 1,
- ...props
- }) {
- return super.updateGestureConfig({
- shouldCancelWhenOutside,
- numberOfTaps,
- maxDeltaX,
- maxDeltaY,
- minDurationMs,
- maxDelayMs,
- maxDist,
- minPointers,
- maxPointers,
- ...props,
- });
- }
-
- onGestureEnded(...props: any) {
- clearTimeout(this._timer);
- // @ts-ignore TODO(TS) check how onGestureEnded works
- super.onGestureEnded(...props);
- }
-
- onWaitingEnded(_gesture: any) {
- if (this._shouldFireEndEvent) {
- this.onSuccessfulTap(this._shouldFireEndEvent);
- this._shouldFireEndEvent = null;
- }
- }
-}
-export default TapGestureHandler;
diff --git a/src/web_hammer/constants.ts b/src/web_hammer/constants.ts
deleted file mode 100644
index 71b792b7c7..0000000000
--- a/src/web_hammer/constants.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import Hammer from '@egjs/hammerjs';
-
-import { State } from '../State';
-
-export const CONTENT_TOUCHES_DELAY = 240;
-export const CONTENT_TOUCHES_QUICK_TAP_END_DELAY = 50;
-export const MULTI_FINGER_PAN_MAX_PINCH_THRESHOLD = 0.1;
-export const MULTI_FINGER_PAN_MAX_ROTATION_THRESHOLD = 7;
-export const DEG_RAD = Math.PI / 180;
-
-// Map Hammer values to RNGH
-export const EventMap = {
- [Hammer.INPUT_START]: State.BEGAN,
- [Hammer.INPUT_MOVE]: State.ACTIVE,
- [Hammer.INPUT_END]: State.END,
- [Hammer.INPUT_CANCEL]: State.FAILED,
-} as const;
-
-export const Direction = {
- RIGHT: 1,
- LEFT: 2,
- UP: 4,
- DOWN: 8,
-};
-
-export const DirectionMap = {
- [Hammer.DIRECTION_RIGHT]: Direction.RIGHT,
- [Hammer.DIRECTION_LEFT]: Direction.LEFT,
- [Hammer.DIRECTION_UP]: Direction.UP,
- [Hammer.DIRECTION_DOWN]: Direction.DOWN,
-};
-
-export const HammerInputNames = {
- [Hammer.INPUT_START]: 'START',
- [Hammer.INPUT_MOVE]: 'MOVE',
- [Hammer.INPUT_END]: 'END',
- [Hammer.INPUT_CANCEL]: 'CANCEL',
-};
-export const HammerDirectionNames = {
- [Hammer.DIRECTION_HORIZONTAL]: 'HORIZONTAL',
- [Hammer.DIRECTION_UP]: 'UP',
- [Hammer.DIRECTION_DOWN]: 'DOWN',
- [Hammer.DIRECTION_VERTICAL]: 'VERTICAL',
- [Hammer.DIRECTION_NONE]: 'NONE',
- [Hammer.DIRECTION_ALL]: 'ALL',
- [Hammer.DIRECTION_RIGHT]: 'RIGHT',
- [Hammer.DIRECTION_LEFT]: 'LEFT',
-};
diff --git a/src/web_hammer/utils.ts b/src/web_hammer/utils.ts
deleted file mode 100644
index 8886395db2..0000000000
--- a/src/web_hammer/utils.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-// TODO(TS) remove if not necessary after rewrite
-export const isnan = (v: unknown) => Number.isNaN(v);
-
-// TODO(TS) remove if not necessary after rewrite
-export const isValidNumber = (v: unknown) =>
- typeof v === 'number' && !Number.isNaN(v);
-
-export const TEST_MIN_IF_NOT_NAN = (value: number, limit: number): boolean =>
- !isnan(limit) &&
- ((limit < 0 && value <= limit) || (limit >= 0 && value >= limit));
-export const VEC_LEN_SQ = ({ x = 0, y = 0 } = {}) => x * x + y * y;
-export const TEST_MAX_IF_NOT_NAN = (value: number, max: number) =>
- !isnan(max) && ((max < 0 && value < max) || (max >= 0 && value > max));
-
-export function fireAfterInterval(
- method: () => void,
- interval?: number | boolean
-) {
- if (!interval) {
- method();
- return null;
- }
- return setTimeout(() => method(), interval as number);
-}
diff --git a/yarn.lock b/yarn.lock
index 7e90b3ff58..ebb02e110d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2729,13 +2729,6 @@
gonzales-pe "^4.3.0"
node-source-walk "^5.0.1"
-"@egjs/hammerjs@^2.0.17":
- version "2.0.17"
- resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124"
- integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==
- dependencies:
- "@types/hammerjs" "^2.0.36"
-
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
@@ -3709,11 +3702,6 @@
dependencies:
"@types/node" "*"
-"@types/hammerjs@^2.0.36":
- version "2.0.41"
- resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.41.tgz#f6ecf57d1b12d2befcce00e928a6a097c22980aa"
- integrity sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==
-
"@types/hoist-non-react-statics@^3.3.1":
version "3.3.1"
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"