diff --git a/packages/docs-gesture-handler/docs/fundamentals/callbacks-events.mdx b/packages/docs-gesture-handler/docs/fundamentals/callbacks-events.mdx
new file mode 100644
index 0000000000..8e9609d6a3
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/fundamentals/callbacks-events.mdx
@@ -0,0 +1,217 @@
+---
+id: callbacks-events
+title: Gesture callbacks & events
+sidebar_label: Gesture callbacks & events
+sidebar_position: 5
+---
+
+import {GestureEventFlowChart, TouchEventFlowChart} from '@site/src/examples/CallbacksFlowCharts'
+import CollapsibleCode from '@site/src/components/CollapsibleCode';
+
+At any given time, each handler instance has an assigned [state](/docs/under-the-hood/state) that can change when new touch events occur or can be forced to change by the touch system in certain circumstances. You can hook into state transitions using specific [gesture callbacks](#callbacks).
+
+## Callbacks flow
+
+### GestureEvent callbacks
+
+
+
+Note that some of these callbacks are complementary:
+
+- if `onBegin` was called, it is guaranteed that `onFinalize` will be called later.
+- if `onActivate` was called, it is guaranteed that `onDeactivate` will be called later.
+
+### TouchEvent callbacks
+
+
+
+## Callbacks
+
+### onBegin
+
+```ts
+onBegin: (event: GestureEvent) => void
+```
+
+Called when a handler begins to recognize gestures. If `onBegin` was called, it is guaranteed that `onFinalize` will be called later.
+
+### onActivate
+
+```ts
+onActivate: (event: GestureEvent) => void
+```
+
+Called when activation criteria for handler are met. If `onActivate` was called, it is guaranteed that `onDeactivate` will be called later.
+
+### onUpdate
+
+```ts
+onUpdate: (event: GestureEvent) => void
+```
+
+Called every time a gesture is updated after it has started.
+
+### onDeactivate
+
+```ts
+onDeactivate: (event: GestureEvent, didSucceed: boolean) => void
+```
+
+Called after when handler stops recognizing gestures, but only if handler activated. It is called before `onFinalize`. If the handler was interrupted, the `didSucceed` argument is set to `false`. Otherwise it is set to `true`.
+
+### onFinalize
+
+```ts
+onFinalize: (event: GestureEvent, didSucceed: boolean) => void
+```
+
+Called when handler stops recognizing gestures. If handler managed to activate, the `didSucceed` argument is set to `true` and `onFinalize` will be called right after `onDeactivate`. Otherwise it is set to `false`.
+
+### onTouchesDown
+
+```ts
+onTouchesDown: (event: GestureTouchEvent) => void
+```
+
+Called when new pointers are placed on the screen. It may carry information about more than one pointer because the events are batched.
+
+### onTouchesMove
+
+```ts
+onTouchesMove: (event: GestureTouchEvent) => void
+```
+
+Called when pointers are moved on the screen. It may carry information about more than one pointer because the events are batched.
+
+### onTouchesUp
+
+```ts
+onTouchesUp: (event: GestureTouchEvent) => void
+```
+
+Called when pointers are lifted from the screen. It may carry information about more than one pointer because the events are batched.
+
+### onTouchesCancelled
+
+```ts
+onTouchesCancelled: (event: GestureTouchEvent) => void
+```
+
+Called when there will be no more information about this pointer. It may be called because the gesture has ended or was interrupted. It may carry information about more than one pointer because the events are batched.
+
+## Events
+
+### GestureEvent
+
+ = {
+ handlerTag: number;
+ numberOfPointers: number;
+ pointerType: PointerType;
+} & HandlerData;
+
+export enum PointerType {
+ TOUCH,
+ STYLUS,
+ MOUSE,
+ KEY,
+ OTHER,
+}
+`}/>
+
+`GestureEvent` contains properties common to all gestures (`handlerTag`, `numberOfPointers`, `pointerType`) along with gesture-specific data defined in each gesture's documentation.
+
+### TouchEvent
+
+
+
+`TouchEvent` carries information about raw touch events, like touching the screen or moving the finger.
+
+## Automatic [workletization](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary/#to-workletize) of gesture callbacks
+
+[Worklets' Babel plugin](https://docs.swmansion.com/react-native-worklets/docs/worklets-babel-plugin/about) is setup in a way that automatically marks callbacks passed to gestures in the configuration chain as worklets. This means that you don't need to add a `'worklet';` directive at the beginning of the functions. Here is an example that will be automatically workletized:
+
+```jsx
+const gesture = useTapGesture({
+ onBegin: () => {
+ console.log(_WORKLET);
+ },
+})
+```
+
+And here is one that won't:
+
+```jsx
+const callback = () => {
+ console.log(_WORKLET);
+};
+
+const gesture = useTapGesture({
+ onBegin: callback,
+})
+```
+
+In the above case, you should add a [`"worklet";`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary/#worklet) directive at the beginning of the callbacks, like so:
+
+```jsx
+const callback = () => {
+ // highlight-next-line
+ "worklet";
+ console.log(_WORKLET);
+};
+
+const gesture = useTapGesture({
+ onBegin: callback,
+})
+```
diff --git a/packages/docs-gesture-handler/docs/fundamentals/state-manager.md b/packages/docs-gesture-handler/docs/fundamentals/state-manager.md
new file mode 100644
index 0000000000..b3b0864141
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/fundamentals/state-manager.md
@@ -0,0 +1,79 @@
+---
+id: state-manager
+title: State manager
+sidebar_label: State manager
+sidebar_position: 6
+---
+
+RNGH3 allows to manually control gestures lifecycle by using `GestureStateManager`.
+
+## State management
+
+Manual state management is based on `handlerTag`. There are two ways of manual state control.
+
+### Inside gesture definition
+
+If you want to manipulate gesture's state in its callbacks, you can get `handlerTag` from event parameter.
+
+```tsx {3}
+const longPress = useLongPressGesture({
+ onTouchesDown: (e) => {
+ GestureStateManager.activate(e.handlerTag);
+ },
+ onActivate: () => {
+ console.log('LongPress activated!');
+ },
+});
+```
+
+### Outside gesture definition
+
+If you want to control gesture lifecycle outside of it, you can use `handlerTag` from created gesture object.
+
+```tsx {9}
+const longPress = useLongPressGesture({
+ onActivate: () => {
+ console.log('LongPress activated!');
+ },
+});
+
+const pan = usePanGesture({
+ onBegin: () => {
+ GestureStateManager.activate(longPress.handlerTag);
+ },
+});
+```
+
+## Methods
+
+### begin
+
+```tsx
+begin: (handlerTag: number) => void;
+```
+
+Triggers [`onBegin`](/docs/fundamentals/callbacks-events#onbegin) callback on gesture with specified `handlerTag`.
+
+### activate
+
+```tsx
+activate: (handlerTag: number) => void;
+```
+
+Triggers [`onActivate`](/docs/fundamentals/callbacks-events#onactivate) callback on gesture with specified `handlerTag`.
+
+### deactivate
+
+```tsx
+deactivate: (handlerTag: number) => void;
+```
+
+Triggers first [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate), then [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) callbacks on gesture with specified `handlerTag`.
+
+### fail
+
+```tsx
+fail: (handlerTag: number) => void;
+```
+
+Triggers [`onFinalize`](/docs/fundamentals/callbacks-events#onfinalize) callback on gesture with specified `handlerTag`. If gesture had activated, it will also trigger [`onDeactivate`](/docs/fundamentals/callbacks-events#ondeactivate) callback.
diff --git a/packages/docs-gesture-handler/docs/fundamentals/states-events.mdx b/packages/docs-gesture-handler/docs/fundamentals/states-events.mdx
deleted file mode 100644
index 44d603e441..0000000000
--- a/packages/docs-gesture-handler/docs/fundamentals/states-events.mdx
+++ /dev/null
@@ -1,89 +0,0 @@
----
-id: states-events
-title: Gesture states & events
-sidebar_label: Gesture states & events
-sidebar_position: 5
----
-
-Every gesture can be treated as ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine).
-At any given time, each handler instance has an assigned state that can change when new touch events occur or can be forced to change by the touch system in certain circumstances.
-
-A gesture can be in one of the six possible states:
-
-- #### UNDETERMINED
-
- This is the initial state of each gesture recognizer and it goes into this state after it's done recognizing a gesture.
-
-- #### FAILED
-
- A gesture recognizer received some touches but for some reason didn't recognize them. For example, if a finger travels more distance than a defined `maxDist` property allows, then the gesture won't become active but will fail instead. Afterwards, it's state will be reset to `UNDETERMINED`.
-
-- #### BEGAN
-
- Gesture recognizer has started receiving touch stream but hasn't yet received enough data to either [fail](#failed) or [activate](#active).
-
-- #### CANCELLED
-
- The gesture recognizer has received a signal (possibly new touches or a command from the touch system controller) resulting in the cancellation of a continuous gesture. The gesture's state will become `CANCELLED` until it is finally reset to the initial state, `UNDETERMINED`.
-
-- #### ACTIVE
-
- Recognizer has recognized a gesture. It will become and stay in the `ACTIVE` state until the gesture finishes (e.g. when user lifts the finger) or gets cancelled by the touch system. Under normal circumstances the state will then turn into `END`. In the case that a gesture is cancelled by the touch system, its state would then become `CANCELLED`.
-
-- #### END
-
- The gesture recognizer has received touches signalling the end of a gesture. Its state will become `END` until it is reset to `UNDETERMINED`.
-
-## State flows
-
-The most typical flow of state is when a gesture picks up on an initial touch event, then recognizes it, then acknowledges its ending and resets itself back to the initial state.
-
-The flow looks as follows:
-
-import GestureStateFlowExample from '@site/src/examples/GestureStateFlowExample';
-
-}
- label="Drag or long-press the circle"
- larger={true}
-/>
-
-## Events
-
-There are three types of events in RNGH2: `StateChangeEvent`, `GestureEvent` and `PointerEvent`. The `StateChangeEvent` is send every time a gesture moves to a different state, while `GestureEvent` is send every time a gesture is updated. The first two carry a gesture-specific data and a `state` property, indicating the current state of the gesture. `StateChangeEvent` also carries a `oldState` property indicating the previous state of the gesture. `PointerEvent` carries information about raw touch events, like touching the screen or moving the finger. These events are handled internally before they are passed along to the correct callbacks:
-
-### `onBegin`
-
-Is called when a gesture transitions to the [`BEGAN`](#began) state.
-
-### `onStart`
-
-Is called when a gesture transitions to the [`ACTIVE`](#active) state.
-
-### `onEnd`
-
-Is called when a gesture transitions from the [`ACTIVE`](#active) state to the [`END`](#end), [`FAILED`](#failed), or [`CANCELLED`](#cancelled) state. If the gesture transitions to the [`END`](#end) state, the `success` argument is set to `true` otherwise it is set to `false`.
-
-### `onFinalize`
-
-Is called when a gesture transitions to the [`END`](#end), [`FAILED`](#failed), or [`CANCELLED`](#cancelled) state. If the gesture transitions to the [`END`](#end) state, the `success` argument is set to `true` otherwise it is set to `false`. If the gesture transitions from the [`ACTIVE`](#active) state, it will be called after `onEnd`.
-
-### `onUpdate`
-
-Is called every time a gesture is updated while it is in the [`ACTIVE`](#active) state.
-
-### `onPointerDown`
-
-Is called when new pointers are placed on the screen. It may carry information about more than one pointer because the events are batched.
-
-### `onPointerMove`
-
-Is called when pointers are moved on the screen. It may carry information about more than one pointer because the events are batched.
-
-### `onPointerUp`
-
-Is called when pointers are lifted from the screen. It may carry information about more than one pointer because the events are batched.
-
-### `onPointerCancelled`
-
-Is called when there will be no more information about this pointer. It may be called because the gesture has ended or was interrupted. It may carry information about more than one pointer because the events are batched.
diff --git a/packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step1.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step1.md
similarity index 63%
rename from packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step1.md
rename to packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step1.md
index 4c6331c1c8..040cb97cb3 100644
--- a/packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step1.md
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step1.md
@@ -1,7 +1,7 @@
-```jsx
-interface Pointer {
- visible: boolean;
+```tsx
+type Pointer = {
x: number;
y: number;
-}
+ visible: boolean;
+};
```
diff --git a/packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step2.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step2.md
similarity index 75%
rename from packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step2.md
rename to packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step2.md
index 40079ee2bd..d02ade2d45 100644
--- a/packages/docs-gesture-handler/docs/guides/manual-gestures/_steps/step2.md
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step2.md
@@ -1,14 +1,22 @@
-```jsx
+```tsx
import { StyleSheet } from 'react-native';
import Animated, {
useAnimatedStyle,
- useSharedValue,
+ SharedValue,
} from 'react-native-reanimated';
-function PointerElement(props: {
- pointer: Animated.SharedValue,
- active: Animated.SharedValue,
-}) {
+type Pointer = {
+ x: number;
+ y: number;
+ visible: boolean;
+};
+
+type PointerElementProps = {
+ pointer: SharedValue;
+ active: SharedValue;
+};
+
+function PointerElement(props: PointerElementProps) {
const animatedStyle = useAnimatedStyle(() => ({
transform: [
{ translateX: props.pointer.value.x },
@@ -25,8 +33,6 @@ function PointerElement(props: {
return ;
}
-// ...
-
const styles = StyleSheet.create({
pointer: {
width: 60,
diff --git a/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step3.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step3.md
new file mode 100644
index 0000000000..3a9160e04a
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step3.md
@@ -0,0 +1,55 @@
+```tsx
+import { StyleSheet } from 'react-native';
+import {
+ GestureDetector,
+ GestureHandlerRootView,
+ GestureStateManager,
+ useManualGesture,
+} from 'react-native-gesture-handler';
+import Animated, {
+ useAnimatedStyle,
+ SharedValue,
+ useSharedValue,
+} from 'react-native-reanimated';
+
+...
+
+export default function Example() {
+ const trackedPointers: SharedValue[] = [];
+ const active = useSharedValue(false);
+
+ for (let i = 0; i < 10; i++) {
+ trackedPointers[i] = useSharedValue({
+ x: 0,
+ y: 0,
+ visible: false,
+ });
+ }
+
+ const gesture = useManualGesture({});
+
+ return (
+
+
+
+ {trackedPointers.map((pointer, index) => (
+
+ ))}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ pointer: {
+ width: 60,
+ height: 60,
+ borderRadius: 30,
+ backgroundColor: 'red',
+ position: 'absolute',
+ marginStart: -30,
+ marginTop: -30,
+ },
+});
+```
diff --git a/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step4.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step4.md
new file mode 100644
index 0000000000..8a8e773ed1
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step4.md
@@ -0,0 +1,17 @@
+```tsx
+const gesture = useManualGesture({
+ onTouchesDown: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+
+ if (e.numberOfTouches >= 2) {
+ GestureStateManager.activate(e.handlerTag);
+ }
+ },
+});
+```
diff --git a/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step5.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step5.md
new file mode 100644
index 0000000000..c27d7cb5bb
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step5.md
@@ -0,0 +1,14 @@
+```tsx
+const gesture = useManualGesture({
+ ...
+ onTouchesMove: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+ },
+});
+```
diff --git a/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step6.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step6.md
new file mode 100644
index 0000000000..c232d392ff
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step6.md
@@ -0,0 +1,18 @@
+```tsx
+const gesture = useManualGesture({
+ ...
+ onTouchesUp: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: false,
+ };
+ }
+
+ if (e.numberOfTouches === 0) {
+ GestureStateManager.deactivate(e.handlerTag);
+ }
+ },
+});
+```
diff --git a/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step7.md b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step7.md
new file mode 100644
index 0000000000..c9da993477
--- /dev/null
+++ b/packages/docs-gesture-handler/docs/gestures/_manual_gesture_steps/step7.md
@@ -0,0 +1,10 @@
+```tsx
+const gesture = useManualGesture({
+ ...
+ onActivate: () => {
+ active.value = true;
+ },
+ onDeactivate: () => {
+ active.value = false;
+ },
+```
diff --git a/packages/docs-gesture-handler/docs/gestures/_shared/base-continuous-gesture-config.md b/packages/docs-gesture-handler/docs/gestures/_shared/base-continuous-gesture-config.md
index 00b24ecba9..c4b1b4056e 100644
--- a/packages/docs-gesture-handler/docs/gestures/_shared/base-continuous-gesture-config.md
+++ b/packages/docs-gesture-handler/docs/gestures/_shared/base-continuous-gesture-config.md
@@ -4,4 +4,4 @@
manualActivation: boolean | SharedValue;
```
-When `true` the handler will not activate by itself even if its activation criteria are met. Instead you can manipulate its state using [state manager](/docs/gestures/state-manager/).
+When `true` the handler will not activate by itself even if its activation criteria are met. Instead you can manipulate its state using [state manager](/docs/fundamentals/state-manager/).
diff --git a/packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-config.md b/packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-config.md
index 76278eac23..fff4295623 100644
--- a/packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-config.md
+++ b/packages/docs-gesture-handler/docs/gestures/_shared/base-gesture-config.md
@@ -5,8 +5,8 @@ enabled: boolean | SharedValue;
```
Indicates whether the given handler should be analyzing stream of touch events or not.
-When set to `false` we can be sure that the handler's state will **never** become [`ACTIVE`](/docs/fundamentals/states-events#active).
-If the value gets updated while the handler already started recognizing a gesture, then the handler's state it will immediately change to [`FAILED`](/docs/fundamentals/states-events#failed) or [`CANCELLED`](/docs/fundamentals/states-events#cancelled) (depending on its current state).
+When set to `false` we can be sure that the handler will **never** activate.
+If the value gets updated while the handler already started recognizing a gesture, then the handler will stop processing gestures immediately.
Default value is `true`.
### shouldCancelWhenOutside
@@ -15,7 +15,7 @@ Default value is `true`.
shouldCancelWhenOutside: boolean | SharedValue;
```
-When `true` the handler will [cancel](/docs/fundamentals/states-events#cancelled) or [fail](/docs/fundamentals/states-events#failed) recognition (depending on its current state) whenever the finger leaves the area of the connected view.
+When `true` the handler will stop recognition whenever the finger leaves the area of the connected view.
Default value of this property is different depending on the handler type.
Most handlers' `shouldCancelWhenOutside` property defaults to `false` except for the [`LongPressGesture`](/docs/gestures/use-long-press-gesture) and [`TapGesture`](/docs/gestures/use-tap-gesture) which default to `true`.
@@ -42,7 +42,7 @@ type HitSlop =
| Record<'height' | 'bottom', number>;
```
-This parameter enables control over what part of the connected view area can be used to [begin](/docs/fundamentals/states-events#began) recognizing the gesture.
+This parameter enables control over what part of the connected view area can be used to begin recognizing the gesture.
When a negative number is provided the bounds of the view will reduce the area by the given number of points in each of the sides evenly.
Instead you can pass an object to specify how each boundary side should be reduced by providing different number of points for `left`, `right`, `top` or `bottom` sides.
@@ -69,7 +69,7 @@ cancelsTouchesInView: boolean | SharedValue;
```
Accepts a boolean value.
-When `true`, the gesture will cancel touches for native UI components (`UIButton`, `UISwitch`, etc) it's attached to when it becomes [`ACTIVE`](/docs/fundamentals/states-events#active).
+When `true`, the gesture will cancel touches for native UI components (`UIButton`, `UISwitch`, etc) it's attached to upon activation.
Default value is `true`.
### runOnJS
diff --git a/packages/docs-gesture-handler/docs/gestures/state-manager.md b/packages/docs-gesture-handler/docs/gestures/state-manager.md
deleted file mode 100644
index f4c39cdfdc..0000000000
--- a/packages/docs-gesture-handler/docs/gestures/state-manager.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-id: state-manager
-title: Gesture state manager
-sidebar_label: Gesture state manager
-sidebar_position: 15
----
-
-`GestureStateManager` allows to manually control the state of the gestures. Please note that `react-native-reanimated` is required to use it, since it allows for synchronously executing methods in worklets.
-
-## Methods
-
-### `begin()`
-
-Transition the gesture to the [`BEGAN`](/docs/2.x/fundamentals/states-events#began) state. This method will have no effect if the gesture has already activated or finished.
-
-### `activate()`
-
-Transition the gesture to the [`ACTIVE`](/docs/2.x/fundamentals/states-events#active) state. This method will have no effect if the handler is already active, or has finished.
-If the gesture is [`exclusive`](/docs/2.x/fundamentals/gesture-composition) with another one, the activation will be delayed until the gesture with higher priority fails.
-
-### `end()`
-
-Transition the gesture to the [`END`](/docs/2.x/fundamentals/states-events#end) state. This method will have no effect if the handler has already finished.
-
-### `fail()`
-
-Transition the gesture to the [`FAILED`](/docs/2.x/fundamentals/states-events#failed) state. This method will have no effect if the handler has already finished.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-fling-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-fling-gesture.mdx
index 5cb582966a..4aa6c21118 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-fling-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-fling-gesture.mdx
@@ -31,8 +31,8 @@ import BaseGestureCallbacks from './\_shared/base-gesture-callbacks.mdx';
import SharedValueInfo from './\_shared/shared-value-info.md';
A discrete gesture that activates when the movement is sufficiently long and fast.
-Gesture gets [ACTIVE](/docs/fundamentals/states-events#active) when movement is sufficiently long and it does not take too much time.
-When gesture gets activated it will turn into [END](/docs/fundamentals/states-events#end) state when finger is released.
+Gesture activates when movement is sufficiently long and it does not take too much time.
+When gesture gets activated it will end when finger is released.
The gesture will fail to recognize if the finger is lifted before being activated.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
index 69c832b82f..811b2dd365 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-long-press-gesture.mdx
@@ -31,7 +31,7 @@ import BaseGestureCallbacks from './\_shared/base-gesture-callbacks.mdx';
import SharedValueInfo from './\_shared/shared-value-info.md';
A discrete gesture that activates when the corresponding view is pressed for a sufficiently long time.
-This gesture's state will turn into [END](/docs/fundamentals/states-events#end) immediately after the finger is released.
+This gesture's state will end immediately after the finger is released.
The gesture will fail to recognize a touch event if the finger is lifted before the minimum required time or if the finger is moved further than the allowable distance.
@@ -102,7 +102,7 @@ Minimum time, expressed in milliseconds, that a finger must remain pressed on th
maxDistance: number | SharedValue;
```
-Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a long press gesture. If the finger travels further than the defined distance and the gesture hasn't yet [activated](/docs/fundamentals/states-events#active), it will fail to recognize the gesture. The default value is 10.
+Maximum distance, expressed in points, that defines how far the finger is allowed to travel during a long press gesture. If the finger travels further than the defined distance and the gesture hasn't yet activated, it will fail to recognize the gesture. The default value is 10.
### mouseButton (Web & Android only)
diff --git a/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
index b4c5545785..2128b2634d 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-manual-gesture.mdx
@@ -11,32 +11,193 @@ import BaseGestureCallbacks from './\_shared/base-gesture-callbacks.mdx';
import BaseContinuousGestureCallbacks from './\_shared/base-continuous-gesture-callbacks.mdx';
import SharedValueInfo from './\_shared/shared-value-info.md';
+import Step, { Divider } from '@site/src/theme/Step';
+import Step1 from './\_manual_gesture_steps/step1.md';
+import Step2 from './\_manual_gesture_steps/step2.md';
+import Step3 from './\_manual_gesture_steps/step3.md';
+import Step4 from './\_manual_gesture_steps/step4.md';
+import Step5 from './\_manual_gesture_steps/step5.md';
+import Step6 from './\_manual_gesture_steps/step6.md';
+import Step7 from './\_manual_gesture_steps/step7.md';
-A plain gesture that has no specific activation criteria nor event data set. Its state has to be controlled manually using a [state manager](/docs/gestures/state-manager). It will not fail when all the pointers are lifted from the screen.
+
+A plain gesture that has no specific activation criteria nor event data set. Its state has to be controlled manually using a [state manager](/docs/fundamentals/state-manager). It will not fail when all the pointers are lifted from the screen.
## Example
-```jsx
+To demonstrate how to make a manual gesture we will make a simple one that tracks all pointers on the screen.
+
+
+ First, we need a way to store information about the pointer: whether it should be visible and its position.
+
+
+
+
+ We also need a component to mark where a pointer is. In order to accomplish that we will make a component that accepts two [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value): one holding information about the pointer using the interface we just created, the other holding a bool indicating whether the gesture has activated.
+ In this example when the gesture is not active, the ball representing it will be blue and when it is active the ball will be red and slightly bigger.
+
+
+
+
+ Now we have to make a component that will handle the gesture and draw all the pointer indicators. We will store data about pointers in an array and render them inside an [`Animated.View`](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/your-first-animation#using-an-animated-component).
+
+
+
+
+ We have our components set up and we can finally get to making the gesture! We will start with `onTouchesDown` where we need to set position of the pointers and make them visible. We can get this information from the touches property of the event. In this case we will also check how many pointers are on the screen and activate the gesture if there are at least two.
+
+
+
+
+ Next, we will handle pointer movement. In `onTouchesMove` we will simply update the position of moved pointers.
+
+
+
+
+ We also need to handle lifting fingers from the screen, which corresponds to `onTouchesUp`. Here we will just hide the pointers that were lifted and end the gesture if there are no more pointers on the screen.
+ Note that we are not handling `onTouchesCancelled` as in this very basic case we don't expect it to happen, however you should clear data about cancelled pointers (most of the time all active ones) when it is called.
+
+
+
+
+ Now that our pointers are being tracked correctly and we have the state management, we can handle activation and ending of the gesture. In our case, we will simply set the active shared value either to `true` or `false`.
+
+
+
+
+Full example code
+
+```tsx
+import { StyleSheet } from 'react-native';
import {
GestureDetector,
GestureHandlerRootView,
+ GestureStateManager,
useManualGesture,
} from 'react-native-gesture-handler';
-import Animated from 'react-native-reanimated';
+import Animated, {
+ useAnimatedStyle,
+ SharedValue,
+ useSharedValue,
+} from 'react-native-reanimated';
+
+type Pointer = {
+ x: number;
+ y: number;
+ visible: boolean;
+};
+
+type PointerElementProps = {
+ pointer: SharedValue;
+ active: SharedValue;
+};
-export default function App() {
- const manualGesture = useManualGesture({});
+function PointerElement(props: PointerElementProps) {
+ const animatedStyle = useAnimatedStyle(() => ({
+ transform: [
+ { translateX: props.pointer.value.x },
+ { translateY: props.pointer.value.y },
+ {
+ scale:
+ (props.pointer.value.visible ? 1 : 0) *
+ (props.active.value ? 1.3 : 1),
+ },
+ ],
+ backgroundColor: props.active.value ? 'red' : 'blue',
+ }));
+
+ return ;
+}
+
+export default function Example() {
+ const trackedPointers: SharedValue[] = [];
+ const active = useSharedValue(false);
+
+ for (let i = 0; i < 10; i++) {
+ trackedPointers[i] = useSharedValue({
+ x: 0,
+ y: 0,
+ visible: false,
+ });
+ }
+
+ const gesture = useManualGesture({
+ onTouchesDown: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+
+ if (e.numberOfTouches >= 2) {
+ GestureStateManager.activate(e.handlerTag);
+ }
+ },
+ onTouchesMove: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: true,
+ };
+ }
+ },
+ onTouchesUp: (e) => {
+ for (const touch of e.changedTouches) {
+ trackedPointers[touch.id].value = {
+ x: touch.x,
+ y: touch.y,
+ visible: false,
+ };
+ }
+
+ if (e.numberOfTouches === 0) {
+ GestureStateManager.deactivate(e.handlerTag);
+ }
+ },
+ onActivate: () => {
+ active.value = true;
+ },
+ onDeactivate: () => {
+ active.value = false;
+ },
+ });
return (
-
-
+
+
+ {trackedPointers.map((pointer, index) => (
+
+ ))}
+
);
}
+
+const styles = StyleSheet.create({
+ pointer: {
+ width: 60,
+ height: 60,
+ borderRadius: 30,
+ backgroundColor: 'red',
+ position: 'absolute',
+ marginStart: -30,
+ marginTop: -30,
+ },
+});
```
+
+
+
+## Modifying existing gestures
+
+While manual gestures open great possibilities we are aware that reimplementing pinch or rotation from scratch just because you need to activate in specific circumstances or require position of the fingers, would be a waste of time as those gestures are already available. Therefore, you can use touch events with every gesture to extract more detailed information about the gesture than what the basic events alone provide. We also added a `manualActivation` modifier on all continuous gestures, which prevents the gesture it is applied to from activating automatically, giving you full control over its behavior.
+
## Config
diff --git a/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
index 509a8ae0eb..73f525c703 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-native-gesture.mdx
@@ -97,7 +97,7 @@ Do not use `Native` gesture with components exported by React Native Gesture Han
shouldActivateOnStart: boolean | SharedValue;
```
-When `true`, underlying handler will activate unconditionally when it receives any touches in [`BEGAN`](/docs/fundamentals/states-events#began) or [`UNDETERMINED`](/docs/fundamentals/states-events#undetermined) state.
+When `true`, underlying handler will activate unconditionally when it receives any touches.
### disallowInterruption
@@ -105,7 +105,7 @@ When `true`, underlying handler will activate unconditionally when it receives a
disallowInterruption: boolean | SharedValue;
```
-When `true`, cancels all other gesture handlers when changes its state to [`ACTIVE`](/docs/fundamentals/states-events#active).
+When `true`, cancels all other gesture handlers when activates.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
index d662dddd87..c58c470323 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-pan-gesture.mdx
@@ -34,7 +34,7 @@ import SharedValueInfo from './\_shared/shared-value-info.md';
A continuous gesture that can recognize a panning (dragging) gesture and track its movement.
-The gesture [activates](/docs/fundamentals/states-events#active) when a finger is placed on the screen and moved some initial distance.
+The gesture activates when a finger is placed on the screen and moved some initial distance.
Configurations such as a minimum initial distance, specific vertical or horizontal pan detection and number of fingers required for activation (allowing for multifinger swipes) may be specified.
@@ -128,7 +128,7 @@ If you wish to track the "center of mass" virtual pointer and account for its ch
minDistance: number | SharedValue;
```
-Minimum distance the finger (or multiple finger) need to travel before the gesture [activates](/docs/fundamentals/states-events#active). Expressed in points.
+Minimum distance the finger (or multiple finger) need to travel before the gesture activates. Expressed in points.
### minPointers
@@ -136,7 +136,7 @@ Minimum distance the finger (or multiple finger) need to travel before the gestu
minPointers: number | SharedValue;
```
-A number of fingers that is required to be placed before gesture can [activate](/docs/fundamentals/states-events#active). Should be a higher or equal to 0 integer.
+A number of fingers that is required to be placed before gesture can activate. Should be a higher or equal to 0 integer.
### maxPointers
@@ -144,7 +144,7 @@ A number of fingers that is required to be placed before gesture can [activate](
maxPointers: number | SharedValue;
```
-When the given number of fingers is placed on the screen and gesture hasn't yet [activated](/docs/fundamentals/states-events#active) it will fail recognizing the gesture. Should be a higher or equal to 0 integer.
+When the given number of fingers is placed on the screen and gesture hasn't yet activated it will fail recognizing the gesture. Should be a higher or equal to 0 integer.
### activateAfterLongPress
@@ -152,7 +152,7 @@ When the given number of fingers is placed on the screen and gesture hasn't yet
activateAfterLongPress: number | SharedValue;
```
-Duration in milliseconds of the `LongPress` gesture before `Pan` is allowed to [activate](/docs/fundamentals/states-events#active). If the finger is moved during that period, the gesture will [fail](/docs/fundamentals/states-events#failed). Should be a higher or equal to 0 integer. Default value is 0, meaning no `LongPress` is required to [activate](/docs/fundamentals/states-events#active) the `Pan`.
+Duration in milliseconds of the `LongPress` gesture before `Pan` is allowed to activate. If the finger is moved during that period, the gesture will fail. Should be a higher or equal to 0 integer. Default value is 0, meaning no `LongPress` is required to activate the `Pan`.
### activeOffsetX
diff --git a/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
index 51fb80760a..283911ead6 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-pinch-gesture.mdx
@@ -33,7 +33,7 @@ import BaseContinuousGestureCallbacks from './\_shared/base-continuous-gesture-c
import SharedValueInfo from './\_shared/shared-value-info.md';
A continuous gesture that recognizes pinch gesture. It allows for tracking the distance between two fingers and use that information to scale or zoom your content.
-The gesture [activates](/docs/fundamentals/states-events#active) when fingers are placed on the screen and change their position.
+The gesture activates when fingers are placed on the screen and change their position.
Gesture callback can be used for continuous tracking of the pinch gesture. It provides information about velocity, anchor (focal) point of gesture and scale.
The distance between the fingers is reported as a scale factor. At the beginning of the gesture, the scale factor is 1.0. As the distance between the two fingers increases, the scale factor increases proportionally.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
index 7df09148c1..7e395c132c 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-rotation-gesture.mdx
@@ -34,7 +34,7 @@ import SharedValueInfo from './\_shared/shared-value-info.md';
A continuous gesture that can recognize a rotation gesture and track its movement.
-The gesture [activates](/docs/fundamentals/states-events#active) when fingers are placed on the screen and change position in a proper way.
+The gesture activates when fingers are placed on the screen and change position in a proper way.
Gesture callback can be used for continuous tracking of the rotation gesture. It provides information about the gesture such as the amount rotated, the focal point of the rotation (anchor), and its instantaneous velocity.
diff --git a/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx b/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
index fc61c590b9..25acce6956 100644
--- a/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
+++ b/packages/docs-gesture-handler/docs/gestures/use-tap-gesture.mdx
@@ -37,7 +37,7 @@ The pointers involved in these gestures must not move significantly from their i
The required number of taps and allowed distance from initial position may be configured.
For example, you might configure tap gesture recognizers to detect single taps, double taps, or triple taps.
-In order for a gesture to [activate](/docs/fundamentals/states-events#active), specified gesture requirements such as minPointers, numberOfTaps, maxDistance, maxDuration, and maxDelay (explained below) must be met. Immediately after the gesture [activates](/docs/fundamentals/states-events#active), it will [end](/docs/fundamentals/states-events#end).
+In order for a gesture to activate, specified gesture requirements such as minPointers, numberOfTaps, maxDistance, maxDuration, and maxDelay (explained below) must be met. Immediately after the gesture activates, it will end.