Skip to content

Commit a779b20

Browse files
committed
Merge branch 'main' into @mbert/support-81
2 parents 7cc80ae + 56db030 commit a779b20

File tree

6 files changed

+114
-39
lines changed

6 files changed

+114
-39
lines changed

packages/docs-gesture-handler/docs/fundamentals/installation.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,12 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
9090
export function CustomModal({ children, ...rest }) {
9191
return (
9292
<Modal {...rest}>
93-
<GestureHandlerRootView>
94-
{children}
95-
</GestureHandlerRootView>
93+
<GestureHandlerRootView>{children}</GestureHandlerRootView>
9694
</Modal>
9795
);
9896
}
9997
```
10098

101-
10299
##### Kotlin
103100

104101
Gesture Handler on Android is implemented in Kotlin. If you need to set a specific Kotlin version to be used by the library, set the `kotlinVersion` ext property in `android/build.gradle` file and RNGH will use that version:
@@ -133,10 +130,9 @@ Nonetheless, it's recommended to adapt to the new implementation, as the legacy
133130

134131
#### With [wix/react-native-navigation](https://github.com/wix/react-native-navigation)
135132

136-
If you are using a native navigation library like [wix/react-native-navigation](https://github.com/wix/react-native-navigation) you need to make sure that every screen is wrapped with `GestureHandlerRootView` (you can do this using `gestureHandlerRootHOC` function). This can be done for example at the stage when you register your screens. Here's an example:
133+
If you are using a native navigation library like [wix/react-native-navigation](https://github.com/wix/react-native-navigation) you need to make sure that every screen is wrapped with `GestureHandlerRootView`. This can be done for example at the stage when you register your screens. Here's an example:
137134

138135
```js
139-
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
140136
import { Navigation } from 'react-native-navigation';
141137
import FirstTabScreen from './FirstTabScreen';
142138
import SecondTabScreen from './SecondTabScreen';
@@ -145,22 +141,40 @@ import PushedScreen from './PushedScreen';
145141
export function registerScreens() {
146142
Navigation.registerComponent(
147143
'example.FirstTabScreen',
148-
() => gestureHandlerRootHOC(FirstTabScreen),
144+
() => {
145+
return (
146+
<GestureHandlerRootView>
147+
<FirstTabScreen />
148+
</GestureHandlerRootView>
149+
);
150+
},
149151
() => FirstTabScreen
150152
);
151153
Navigation.registerComponent(
152154
'example.SecondTabScreen',
153-
() => gestureHandlerRootHOC(SecondTabScreen),
155+
() => {
156+
return (
157+
<GestureHandlerRootView>
158+
<SecondTabScreen />
159+
</GestureHandlerRootView>
160+
);
161+
},
154162
() => SecondTabScreen
155163
);
156164
Navigation.registerComponent(
157165
'example.PushedScreen',
158-
() => gestureHandlerRootHOC(PushedScreen),
166+
() => {
167+
return (
168+
<GestureHandlerRootView>
169+
<PushedScreen />
170+
</GestureHandlerRootView>
171+
);
172+
},
159173
() => PushedScreen
160174
);
161175
}
162176
```
163177

164178
You can check out [this example project](https://github.com/henrikra/nativeNavigationGestureHandler) to see this kind of set up in action.
165179

166-
Remember that you need to wrap each screen that you use in your app with `GestureHandlerRootView` (you can do this using `gestureHandlerRootHOC` function) as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only.
180+
Remember that you need to wrap each screen that you use in your app with `GestureHandlerRootView` as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only.

packages/docs-gesture-handler/docs/fundamentals/introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ We recommended to use Reanimated to implement gesture-driven animations with Ges
2525

2626
### Apps
2727

28-
[Gesture Handler Example App](https://github.com/software-mansion/react-native-gesture-handler/blob/main/example) – official gesture handler "showcase" app.
28+
[Gesture Handler Example App](https://github.com/software-mansion/react-native-gesture-handler/tree/main/apps/expo-example) – official gesture handler "showcase" app.
2929

3030
### Talks and workshops
3131

packages/docs-gesture-handler/docs/guides/migrating-off-rnghenabledroot.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ Some libraries (for example React Navigation) already use `GestureHandlerRootVie
3232

3333
## Update your JS code
3434

35-
Instead of using `RNGestureHandlerEnabledRootView` wrap your entry point with `<GestureHandlerRootView>` or `gestureHandlerRootHOC`, for example:
35+
Instead of using `RNGestureHandlerEnabledRootView` wrap your entry point with `<GestureHandlerRootView>`, for example:
3636

3737
```jsx
3838
export default function App() {
39-
return <GestureHandlerRootView style={{ flex: 1 }}>{/* content */}</GestureHandlerRootView>;
39+
return (
40+
<GestureHandlerRootView style={{ flex: 1 }}>
41+
{/* content */}
42+
</GestureHandlerRootView>
43+
);
4044
}
4145
```
4246

4347
:::info
4448
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.
45-
:::
49+
:::

packages/docs-gesture-handler/versioned_docs/version-1.x/getting-started.md

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ or with `npm` if you prefer:
5858
npm install --save react-native-gesture-handler
5959
```
6060

61-
After installation, wrap your entry point with `<GestureHandlerRootView>` or
62-
`gestureHandlerRootHOC`.
61+
After installation, wrap your entry point with `<GestureHandlerRootView>`.
6362

6463
For example:
6564

@@ -131,22 +130,17 @@ public class MainActivity extends ReactActivity {
131130
#### Usage with modals on Android
132131

133132
On Android RNGH does not work by default because modals are not located under React Native Root view in native hierarchy.
134-
To fix that, components need to be wrapped with `gestureHandlerRootHOC` (it's no-op on iOS and web).
133+
To fix that, components need to be wrapped with `GestureHandlerRootView`.
135134

136135
For example:
137136

138137
```js
139-
const ExampleWithHoc = gestureHandlerRootHOC(() => (
140-
<View>
141-
<DraggableBox />
142-
</View>
143-
);
144-
);
145-
146138
export default function Example() {
147139
return (
148140
<Modal>
149-
<ExampleWithHoc />
141+
<GestureHandlerRootView>
142+
<DraggableBox />
143+
</GestureHandlerRootView>
150144
</Modal>
151145
);
152146
}
@@ -173,10 +167,9 @@ import 'react-native-gesture-handler';
173167

174168
If you are using a native navigation library like [wix/react-native-navigation](https://github.com/wix/react-native-navigation) you need to follow a different setup for your Android app to work properly. The reason is that both native navigation libraries and Gesture Handler library need to use their own special subclasses of `ReactRootView`.
175169

176-
Instead of changing Java code you will need to wrap every screen component using `gestureHandlerRootHOC` on the JS side. This can be done for example at the stage when you register your screens. Here's an example:
170+
Instead of changing Java code you will need to wrap every screen component using `GestureHandlerRootView` on the JS side. This can be done for example at the stage when you register your screens. Here's an example:
177171

178172
```js
179-
import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
180173
import { Navigation } from 'react-native-navigation';
181174

182175
import FirstTabScreen from './FirstTabScreen';
@@ -187,25 +180,43 @@ import PushedScreen from './PushedScreen';
187180
export function registerScreens() {
188181
Navigation.registerComponent(
189182
'example.FirstTabScreen',
190-
() => gestureHandlerRootHOC(FirstTabScreen),
183+
() => {
184+
return (
185+
<GestureHandlerRootView>
186+
<FirstTabScreen />
187+
</GestureHandlerRootView>
188+
);
189+
},
191190
() => FirstTabScreen
192191
);
193192
Navigation.registerComponent(
194193
'example.SecondTabScreen',
195-
() => gestureHandlerRootHOC(SecondTabScreen),
194+
() => {
195+
return (
196+
<GestureHandlerRootView>
197+
<SecondTabScreen />
198+
</GestureHandlerRootView>
199+
);
200+
},
196201
() => SecondTabScreen
197202
);
198203
Navigation.registerComponent(
199204
'example.PushedScreen',
200-
() => gestureHandlerRootHOC(PushedScreen),
205+
() => {
206+
return (
207+
<GestureHandlerRootView>
208+
<PushedScreen />
209+
</GestureHandlerRootView>
210+
);
211+
},
201212
() => PushedScreen
202213
);
203214
}
204215
```
205216

206217
You can check out [this example project](https://github.com/henrikra/nativeNavigationGestureHandler) to see this kind of set up in action.
207218

208-
Remember that you need to wrap each screen that you use in your app with `gestureHandlerRootHOC` as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only.
219+
Remember that you need to wrap each screen that you use in your app with `GestureHandlerRootView` as with native navigation libraries each screen maps to a separate root view. It will not be enough to wrap the main screen only.
209220

210221
### Testing
211222

packages/react-native-gesture-handler/src/components/gestureHandlerRootHOC.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import { StyleSheet, StyleProp, ViewStyle } from 'react-native';
33
import hoistNonReactStatics from 'hoist-non-react-statics';
44
import GestureHandlerRootView from './GestureHandlerRootView';
55

6+
/**
7+
* @deprecated `gestureHandlerRootHOC` is deprecated and will be removed in the future version of Gesture Handler.
8+
* Use `GestureHandlerRootView` directly instead.
9+
*/
610
export default function gestureHandlerRootHOC<P extends object>(
711
Component: React.ComponentType<P>,
812
containerStyles?: StyleProp<ViewStyle>

packages/react-native-gesture-handler/src/web/tools/KeyboardEventManager.ts

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,47 @@ import EventManager from './EventManager';
33
import { PointerType } from '../../PointerType';
44

55
export default class KeyboardEventManager extends EventManager<HTMLElement> {
6-
private activationKeys = ['Enter', ' '];
7-
private cancelationKeys = ['Tab'];
6+
private static activationKeys = ['Enter', ' '];
7+
private static cancelationKeys = ['Tab'];
88
private isPressed = false;
9+
private static registeredStaticListeners = false;
10+
private static instances: Set<KeyboardEventManager> = new Set();
11+
12+
private static keyUpStaticCallback = (event: KeyboardEvent): void => {
13+
// We need a global listener, as in some cases, keyUp event gets stop-propagated.
14+
// Then, if we used only component-level listeners the gesture would never end,
15+
// causing other gestues to fail.
16+
17+
if (this.activationKeys.indexOf(event.key) === -1) {
18+
return;
19+
}
20+
21+
this.instances.forEach((item) => {
22+
item.onKeyUp(event);
23+
});
24+
};
925

1026
private keyDownCallback = (event: KeyboardEvent): void => {
11-
if (this.cancelationKeys.indexOf(event.key) !== -1 && this.isPressed) {
27+
if (
28+
KeyboardEventManager.cancelationKeys.indexOf(event.key) !== -1 &&
29+
this.isPressed
30+
) {
1231
this.dispatchEvent(event, EventTypes.CANCEL);
1332
return;
1433
}
1534

16-
if (this.activationKeys.indexOf(event.key) === -1) {
35+
if (KeyboardEventManager.activationKeys.indexOf(event.key) === -1) {
1736
return;
1837
}
1938

2039
this.dispatchEvent(event, EventTypes.DOWN);
2140
};
2241

23-
private keyUpCallback = (event: KeyboardEvent): void => {
24-
if (this.activationKeys.indexOf(event.key) === -1 || !this.isPressed) {
42+
private onKeyUp = (event: KeyboardEvent): void => {
43+
if (
44+
KeyboardEventManager.activationKeys.indexOf(event.key) === -1 ||
45+
!this.isPressed
46+
) {
2547
return;
2648
}
2749

@@ -53,12 +75,32 @@ export default class KeyboardEventManager extends EventManager<HTMLElement> {
5375

5476
public registerListeners(): void {
5577
this.view.addEventListener('keydown', this.keyDownCallback);
56-
this.view.addEventListener('keyup', this.keyUpCallback);
78+
79+
KeyboardEventManager.instances.add(this);
80+
81+
if (!KeyboardEventManager.registeredStaticListeners) {
82+
KeyboardEventManager.registeredStaticListeners = true;
83+
document.addEventListener(
84+
'keyup',
85+
KeyboardEventManager.keyUpStaticCallback,
86+
{ capture: true }
87+
);
88+
}
5789
}
5890

5991
public unregisterListeners(): void {
6092
this.view.removeEventListener('keydown', this.keyDownCallback);
61-
this.view.removeEventListener('keyup', this.keyUpCallback);
93+
94+
KeyboardEventManager.instances.delete(this);
95+
96+
if (KeyboardEventManager.instances.size === 0) {
97+
document.removeEventListener(
98+
'keyup',
99+
KeyboardEventManager.keyUpStaticCallback,
100+
{ capture: true }
101+
);
102+
KeyboardEventManager.registeredStaticListeners = false;
103+
}
62104
}
63105

64106
protected mapEvent(

0 commit comments

Comments
 (0)