diff --git a/packages/docs-gesture-handler/docs/guides/migrating-off-rnghenabledroot.md b/packages/docs-gesture-handler/docs/guides/migrating-off-rnghenabledroot.md deleted file mode 100644 index b777549b33..0000000000 --- a/packages/docs-gesture-handler/docs/guides/migrating-off-rnghenabledroot.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -id: migrating-off-rnghenabledroot -title: Migrating off RNGHEnabledRootView ---- - -## Update `MainActivity.java` - -Update your `MainActivity.java` file (or wherever you create an instance of `ReactActivityDelegate`), so that it no longer overrides the method responsible for creating `ReactRootView` instance, or modify it so that it no longer uses `RNGestureHandlerEnabledRootView`. Do not forget to remove import for `RNGestureHandlerEnabledRootView`: - -```java -package com.swmansion.gesturehandler.react.example; - -import com.facebook.react.ReactActivity; -- import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; -public class MainActivity extends ReactActivity { - -- @Override -- protected ReactActivityDelegate createReactActivityDelegate() { -- return new ReactActivityDelegate(this, getMainComponentName()) { -- @Override -- protected ReactRootView createRootView() { -- return new RNGestureHandlerEnabledRootView(MainActivity.this); -- } -- }; -- } -} -``` - -## Check if your app works correctly - -Some libraries (for example React Navigation) already use `GestureHandlerRootView` as a wrapper to enable gesture interactions. In that case you don't have to add one yourself. If gestures in your app work as expected after removing `RNGestureHandlerEnabledRootView` you can skip the next step. - -## Update your JS code - -Instead of using `RNGestureHandlerEnabledRootView` wrap your entry point with ``, for example: - -```jsx -export default function App() { - return ( - - {/* content */} - - ); -} -``` - -:::info -Note that `GestureHandlerRootView` acts like a normal `View`. So if you want it to fill the screen, you will need to pass `{ flex: 1 }` like you'll need to do with a normal View. By default, it'll take the size of the content nested inside. -::: diff --git a/packages/docs-gesture-handler/docs/guides/troubleshooting.md b/packages/docs-gesture-handler/docs/guides/troubleshooting.md index 0b78fd7926..de9e7a9b4c 100644 --- a/packages/docs-gesture-handler/docs/guides/troubleshooting.md +++ b/packages/docs-gesture-handler/docs/guides/troubleshooting.md @@ -10,7 +10,7 @@ Thanks for giving this library a try! We are sorry that you might have encounter 1. Search over the [issues on Github](https://github.com/software-mansion/react-native-gesture-handler/issues). There is a chance someone had this problem in the past and it has been resolved! 2. When sure your problem hasn't been reported or was reported but the proposed solution doesn't work for you please follow [our issue reporting guidelines](#reporting-issues). -3. You can try seeking help on [Expo Developers Discord](https://chat.expo.dev/) where we often hang out. +3. You can try seeking help on [Software Mansion Discord](discord.com/invite/VemJ4df8Yr). 4. If you feel like reading the source code I highly recommend it, as this is by far the best resource and gives you the most up to date insights into how the library works and what might be causing the bug. 5. If you managed to find the solution consider [contributing](/docs/#contributing) a fix or update our documentation to make this information easier to find for the others in the future. diff --git a/packages/docs-gesture-handler/docs/guides/upgrading-to-2.md b/packages/docs-gesture-handler/docs/guides/upgrading-to-2.md deleted file mode 100644 index 7ba133446b..0000000000 --- a/packages/docs-gesture-handler/docs/guides/upgrading-to-2.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -id: upgrading-to-2 -title: Upgrading to the new API introduced in Gesture Handler 2 ---- - -## Make sure to migrate off the `RNGestureHandlerEnabledRootView` (Android only) - -Gesture Handler 1 required you to override `createRootView` to return an instance of `RNGestureHandlerEnabledRootView`. This class has been the cause of many hard to debug and fix crashed and was deprecated in version 2.0, and subsequently removed in version 2.4. If you are still using it, check out [migrating off RNGHEnabledRootView guide](/docs/guides/migrating-off-rnghenabledroot). - -## Upgrading to the new API - -The most important change brought by the Gesture Handler 2 is the new Gesture API, along with the `GestureDetector` component. It makes declaring gesture easier, as it handles much of the work under the hood and reduces the amount of necessary boilerplate code. Instead of a separate component for every type of gesture, the `GestureDetector` component is used to attach gestures to the underlying view based on the configuration object passed to it. The configuration objects are created using the `Gesture` object, here is a simple example: - -```jsx -const tapGesture = Gesture.Tap().onStart(() => { - console.log('Tap!'); -}); -... -return ( - - - -); -``` - -As you can see, there are no `onGestureEvent` and `onHandlerStateChange` callbacks, instead the state machine is handled under the hood and relevant callbacks are called for specific transitions or events: - -- `onBegin` - called when the gesture transitions to the `BEGAN` state, which in most cases is when the gesture starts processing the touch stream - when the finger first touches the view -- `onStart` - called when the activation criteria for the gesture are met and it transitions from `BEGAN` to `ACTIVE` state -- `onUpdate` - replaces `onGestureEvent`, called every time the gesture sends a new event while it's in the `ACTIVE` state -- `onChange` - if defined, called just after `onUpdate`, the events passed to it are the same as the ones passed to `onUpdate` but they also contain `change` values which hold the change in value they represent since the last event (i.e. in case of the `Pan` gesture, the event will also contain `changeX` and `changeY` properties) -- `onEnd` - called when the gesture transitions from the `ACTIVE` state to either of `END`, `FAILED` or `CANCELLED` - you can tell whether the gesture finished due to user interaction or because of other reason (like getting cancelled by the system, or failure criteria) using the second value passed to the `onEnd` callback alongside the event -- `onFinalize` called when the gesture transitions into either of `END`, `FAILED` or `CANCELLED` state, if the gesture was `ACTIVE`, `onEnd` will be called first (similarly to `onEnd` you can determine the reason for finishing using the second argument) - -The difference between `onEnd` and `onFinalize` is that the `onEnd` will be called only if the gesture was `ACTIVE`, while `onFinalize` will be called if the gesture has `BEGAN`. This means that you can use `onEnd` to clean up after `onStart`, and `onFinalize` to clean up after `onBegin` (or both `onBegin` and `onStart`). - -### Configuring the gestures - -The new gesture objects are configured in the builder-like pattern. Instead of properties, each gesture provides methods that allow for its customization. In most cases the names of the methods are the same as the relevant props, or at least very similar. For example: - -```jsx -return ( - { - if (nativeEvent.state === State.ACTIVE) { - console.log('Tap!'); - } - }}> - - -); -``` - -Would have the same effect as: - -```jsx -const tapGesture = Gesture.Tap() - .numberOfTaps(2) - .maxDuration(500) - .maxDelay(500) - .maxDistance(10) - .onStart(() => { - console.log('Tap!'); - }); - -return ( - - - -); -``` - -You can check the modifiers available to specific gestures in the API Reference under Gestures. - -### Using multiple gestures on the same view - -Using the gesture handler components, if you wanted to have multiple gestures on one view, you would have to stack them on top of each other and, in case you wanted to use animations, add an `Animated.View` after each handler, resulting in a deep component tree, for example: - -```jsx -return ( - - - - - - - - - - - -); -``` - -With the `GestureDetector` you can use the [Gesture Composition API](/docs/fundamentals/gesture-composition) to stack the gestures onto one view: - -```jsx -const tapGesture = Gesture.Tap(); -const panGesture = Gesture.Pan(); -const pinchGesture = Gesture.Pinch(); - -return ( - - - -); -``` - -Similarly, you can use [`Gesture.Simultaneous`](/docs/fundamentals/gesture-composition#simultaneous) to replace stacked gesture handlers that should be able to recognize gestures simultaneously, and [`Gesture.Exclusive`](/docs/fundamentals/gesture-composition#exclusive) to replace stacked gesture handlers that require failure of others. - -### Replacing `waitFor` and `simultaneousHandlers` - -If you want to make relations between the gestures attached to the same view, you should use the [Gesture Composition API](/docs/fundamentals/gesture-composition) described above. However, if you want to make a relation between gestures attached to different views, or between gesture and an old gesture handler, you should use `simultaneousWithExternalGesture` instead of `simultaneousHandlers`, and `requireExternalGestureToFail` instead of `waitFor`. In case you need a ref object to pass to an old gesture handler, you can set it to the gesture using `.withRef(refObject)` modifier. diff --git a/packages/docs-gesture-handler/docs/guides/upgrading-to-3.mdx b/packages/docs-gesture-handler/docs/guides/upgrading-to-3.mdx new file mode 100644 index 0000000000..10da249108 --- /dev/null +++ b/packages/docs-gesture-handler/docs/guides/upgrading-to-3.mdx @@ -0,0 +1,248 @@ +--- +id: upgrading-to-3 +title: Upgrading to the new API introduced in Gesture Handler 3 +--- + +## Migrating gestures + + +import CodeComparison from '@site/src/components/CodeComparison'; + +The most important change brought by the Gesture Handler 3 is the new hook API. Migration is pretty straight-forward. Instead of calling builder methods, everything is passed into configuration object. + + { + console.log('Pan!'); + }) + .minDistance(25); +`} +code2={ +`const gesture = usePanGesture({ + onBegin: () => { + console.log('Pan!'); + }, + minDistance: 25, + }); +`} +/> + +:::danger Force Touch Gesture +[`ForceTouch`](/docs/2.x/gestures/force-touch-gesture) gesture is not available in hook API. +::: + +### Renamed callbacks + +In Gesture Handler 3 some of the callbacks were renamed, namely: + +| RNGH2 | RNGH3 | +| --------- | -------------- | +| `onStart` | `onActivate` | +| `onEnd` | `onDeactivate` | + +Here is comparison of the two APIs: + + { + console.log('Pan started!'); + }) + .onEnd(() => { + console.log('Pan ended!'); + }); +`} +code2={ +`const gesture = usePanGesture({ + onActivate: () => { + console.log('Pan activated!'); + }, + onDeactivate: () => { + console.log('Pan deactivated!'); + }, +}); +`} +/> + +
+Full changes + +| RNGH2 | RNGH3 | +| ---------------------- | ----------------------- | +| `Gesture.Pan()` | `usePanGesture()` | +| `Gesture.Tap()` | `useTapGesture()` | +| `Gesture.LongPress()` | `useLongPressGesture()` | +| `Gesture.Rotation()` | `useRotationGesture()` | +| `Gesture.Pinch()` | `usePinchGesture()` | +| `Gesture.Fling()` | `useFlingGesture()` | +| `Gesture.Hover()` | `useHoverGesture()` | +| `Gesture.Native()` | `useNativeGesture()` | +| `Gesture.Manual()` | `useManualGesture()` | +| `Gesture.ForceTouch()` | | + +{/* */} + +
+ +## Migrating relations + +### Composed gestures + +Previously, composed gestures were created using `Gesture` object. In Gesture Handler 3, relations are set up using relation hooks. + + + +:::danger Race gesture +In Gesture Handler 3 `Race` gesture was renamed to `Competing` gesture. +::: + +### Cross components relations properties + +Properties used to define cross-components interactions were renamed. + + + +
+Full changes + +| RNGH2 | RNGH3 | +| ----------------------------------------- | --------------------------- | +| `Gesture.Race()` | `useCompetingGestures()` | +| `Gesture.Simultaneous()` | `useSimultaneousGestures()` | +| `Gesture.Exclusive()` | `useExclusiveGestures()` | +| | | +| `gesture.simultaneousWithExternalGesture` | `gesture.simultaneousWith` | +| `gesture.requireExternalGestureToFail` | `gesture.requireToFail` | +| `gesture.blocksExternalGesture` | `gesture.block` | + +
+ +## Using SVG + +In Gesture Handler 2 it was possible to use `GestureDetector` directly on `SVG`. In Gesture Handler 3, the correct way to interact with `SVG` is to use `InterceptingGestureDetector` and `VirtualGestureDetector`. + + + + + + + + +`} +code2={ +` + + + + + + + +`} +/> + +:::danger Detectors order +`VirtualGestureDetector` has to be a child of `InterceptingGestureDetector`. +::: + +## Old components + +Components were rewritten to use new hook API. If for some reason you need to use old components, they now also use `Legacy` prefix, e.g. `RectButton` becomes `LegacyRectButton`. + +
+Full changes + +| RNGH2 | RNGH3 | +| --------------------- | --------------------------- | +| `RawButton` | `LegacyRawButton` | +| `BaseButton` | `LegacyBaseButton` | +| `RectButton` | `LegacyRectButton` | +| `BorderlessButton` | `LegacyBorderlessButton` | +| | | +| `ScrollView` | `LegacyScrollView` | +| `FlatList` | `LegacyFlatList` | +| `RefreshControl` | `LegacyRefreshControl` | +| `Switch` | `LegacySwitch` | +| `TextInput` | `LegacyTextInput` | +| `DrawerLayoutAndroid` | `LegacyDrawerLayoutAndroid` | + +
+ +## Replaced types + +Most of the types, like `TapGesture`, are still present in Gesture Handler 3. However, they are now used in new hook API. Types for old API now have `Legacy` prefix, e.g. `TapGesture` becomes `LegacyTapGesture`. + +
+Full changes + +| RNGH2 | RNGH3 | +| ----------------------- | ----------------------------- | +| `PanGesture` | `LegacyPanGesture` | +| `TapGesture` | `LegacyTapGesture` | +| `LongPressGesture` | `LegacyLongPressGesture` | +| `RotationGesture` | `LegacyRotationGesture` | +| `PinchGesture` | `LegacyPinchGesture` | +| `FlingGesture` | `LegacyFlingGesture` | +| `HoverGesture` | `LegacyHoverGesture` | +| `NativeGesture` | `LegacyNativeGesture` | +| `ManualGesture` | `LegacyManualGesture` | +| `ForceTouchGesture` | `LegacyForceTouchGesture` | +| | | +| `ComposedGesture` | `LegacyComposedGesture` | +| `RaceGesture` | `LegacyRaceGesture` | +| `SimultaneousGesture` | `LegacySimultaneousGesture` | +| `ExclusiveGesture` | `LegacyExclusiveGesture` | +| | | +| `RawButtonProps` | `LegacyRawButtonProps` | +| `BaseButtonProps` | `LegacyBaseButtonProps` | +| `RectButtonProps` | `LegacyRectButtonProps` | +| `BorderlessButtonProps` | `LegacyBorderlessButtonProps` | +| | | +| `ScrollView` | `LegacyScrollView` | +| `FlatList` | `LegacyFlatList` | +| `RefreshControl` | `LegacyRefreshControl` | +| `Switch` | `LegacySwitch` | +| `TextInput` | `LegacyTextInput` | +| `DrawerLayoutAndroid` | `LegacyDrawerLayoutAndroid` | + +
diff --git a/packages/docs-gesture-handler/src/components/CodeComparison/index.tsx b/packages/docs-gesture-handler/src/components/CodeComparison/index.tsx new file mode 100644 index 0000000000..22365f443d --- /dev/null +++ b/packages/docs-gesture-handler/src/components/CodeComparison/index.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import CodeBlock from '@theme/CodeBlock'; +import useFormattedCode from '@site/src/hooks/useFormattedCode'; + +export default function CodeComparison({ + label1, + label2, + code1, + code2, + skipFormatting1 = false, + skipFormatting2 = false, +}) { + const formattedCode1 = useFormattedCode(code1); + const formattedCode2 = useFormattedCode(code2); + + return ( +
+
+
{label1}
+ + {skipFormatting1 ? code1 : formattedCode1} + +
+ +
+
{label2}
+ + {skipFormatting2 ? code2 : formattedCode2} + +
+
+ ); +} diff --git a/packages/docs-gesture-handler/src/css/overrides.css b/packages/docs-gesture-handler/src/css/overrides.css index bcab954495..1f62b2cf3f 100644 --- a/packages/docs-gesture-handler/src/css/overrides.css +++ b/packages/docs-gesture-handler/src/css/overrides.css @@ -55,6 +55,14 @@ table thead tr { border: transparent 2px solid; } +details tr { + background: var(--ifm-background-color); +} + +details thead { + background: var(--ifm-background-color); +} + @media (min-width: 996px) { .header-github { margin-left: 1.5em; @@ -111,6 +119,66 @@ table thead tr { font-family: var(--ifm-font-family-monospace); } +table [class*='codeBlockContent'] pre, +table [class*='codeBlockContent'] code { + border:none; + background-color: transparent; + font-family: var(--ifm-font-family-monospace); +} + +.codeCell { + vertical-align: top; + /* padding:0; */ +} + +.codeComparison { + display: flex; + flex-direction: row; + margin-bottom: 20px; + border: 1px solid var(--swm-border); +} + +.codeComparison .codeHolder:first-child { + border-right: 1px solid var(--swm-border); +} + +.codeComparison pre, +.codeComparison code { + border:none; + background-color: transparent; + font-family: var(--ifm-font-family-monospace); + +} + +.codeComparisonHeader { + text-align: center; + font-weight: bold; + padding: 10px; + border-bottom: 1px solid var(--swm-border); +} + +.codeHolder { + width: 50%; +} + +@media (max-width: 996px) { + .codeComparison{ + display: flex; + flex-direction: column; + margin-bottom: 20px; + border: 1px solid var(--swm-border); + } + + .codeComparison .codeHolder:first-child { + border-right: none; + border-bottom: 1px solid var(--swm-border); + } + + .codeHolder { + width: 100%; + } +} + /* Add small padding, when some of the lines are too long in a code block */ [class*='codeBlockLines'] span:last-of-type { margin-right: 1em; diff --git a/packages/docs-gesture-handler/src/hooks/useFormattedCode.tsx b/packages/docs-gesture-handler/src/hooks/useFormattedCode.tsx new file mode 100644 index 0000000000..f127fbb21a --- /dev/null +++ b/packages/docs-gesture-handler/src/hooks/useFormattedCode.tsx @@ -0,0 +1,24 @@ +import { useEffect, useState } from 'react'; +import * as prettier from 'prettier/standalone'; +import tsParser from 'prettier/plugins/typescript'; +import estreeParser from 'prettier/plugins/estree'; + +const prettierOptions = { + parser: 'typescript', + plugins: [tsParser, estreeParser], +}; + +export default function useFormattedCode(code: string) { + const [formattedCode, setFormattedCode] = useState(code); + + useEffect(() => { + async function formatCode() { + const newCode = await prettier.format(code, prettierOptions); + setFormattedCode(newCode); + } + + void formatCode(); + }, [code]); + + return formattedCode; +}