react-native-dodge-keyboard 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,10 +5,11 @@
5
5
  react-native-dodge-keyboard is a tiny, zero-dependency library designed to flawlessly move your UI out of the way of the keyboard.
6
6
  It is built to solve a long-standing React Native pain point: TextInputs inside ScrollViews, FlatLists, and custom scrollable layouts not being properly lifted when focused.
7
7
 
8
- Unlike KeyboardAvoidingView and older third-party libraries, react-native-dodge-keyboard:
8
+ Unlike `KeyboardAvoidingView` and older third-party libraries, react-native-dodge-keyboard:
9
9
 
10
- - Works with any scrollable container
10
+ - Works with any scrollable container (ScrollView, FlatList, SectionList, ...more)
11
11
  - Supports dynamic layout sizes
12
+ - Handles elements that are not inside a scrollable view.
12
13
  - Handles scrollviews placed anywhere (nested, offset, inside modals, bottom sheets, etc.)
13
14
  - Works on both iOS and Android
14
15
  - Requires zero configuration
@@ -27,6 +28,13 @@ or using yarn
27
28
  yarn add react-native-dodge-keyboard
28
29
  ```
29
30
 
31
+ ## Demo
32
+
33
+ <p>
34
+ <img src="https://github.com/deflexable/react-native-dodge-keyboard/blob/main/screenshots/main.gif" width="260">
35
+ <img src="https://github.com/deflexable/react-native-dodge-keyboard/blob/main/screenshots/android_main.gif" width="260">
36
+ </p>
37
+
30
38
  ## Usage
31
39
 
32
40
  Wrap your screen (or only the part you want to dodge) with the DodgeKeyboard component.
@@ -34,18 +42,46 @@ Wrap your screen (or only the part you want to dodge) with the DodgeKeyboard com
34
42
  ### Basic Example
35
43
 
36
44
  ```js
37
- import DodgeKeyboard from 'react-native-dodge-keyboard';
45
+ import { DodgeKeyboard } from 'react-native-dodge-keyboard';
38
46
  import { ScrollView, TextInput } from 'react-native';
39
47
 
40
- export default function TestingScreen() {
48
+ export default function TestScreen() {
41
49
 
42
50
  return (
43
51
  <DodgeKeyboard>
44
- <ScrollView contentContainerStyle={{ flex: 1 }}>
52
+ <ScrollView style={{ flex: 1 }}>
45
53
  <TextInput placeholder="Name" style={styles.input} />
46
54
  <TextInput multiline placeholder="Message" style={styles.multiline} />
47
55
  </ScrollView>
48
56
  </DodgeKeyboard>
49
57
  );
50
58
  }
51
- ```
59
+ ```
60
+
61
+ ## Known Issues
62
+
63
+ ### Android Soft Input
64
+ Some Android devices handle keyboard dodging natively, which can lead to unexpected behavior when used with this library. To disable the native behavior and avoid issues, set `android:windowSoftInputMode="adjustNothing"` in your AndroidManifest.xml.
65
+
66
+ ## Advance Use Cases
67
+
68
+ ### Dodging custom views
69
+ Out of the box, `TextInput` is the only component that supports keyboard dodging. To enable this behavior for other components, pass `dodge_keyboard_input={true}` as a prop.
70
+
71
+ You can also listen to `checkIfElementIsFocused` prop and return whether the element passed as an argument is currently focused and needs to dodge the keyboard.
72
+
73
+ Kindly check [examples/CustomFocusDodge.jsx](https://github.com/deflexable/react-native-dodge-keyboard/blob/main/examples/CustomFocusDodge.jsx) for example on this approach.
74
+
75
+ A demo of the example is attach below:
76
+
77
+ <img src="https://github.com/deflexable/react-native-dodge-keyboard/blob/main/screenshots/custom.gif" width="260">
78
+
79
+
80
+ ### Dodging static element
81
+ To dodge `TextInput` or component with prop `dodge_keyboard_input={true}` that are not inside a scrollable view, you need to listen to `onHandleDodging` to manually lift up the component yourself.
82
+
83
+ Kindly check [examples/ManualLifting.jsx](https://github.com/deflexable/react-native-dodge-keyboard/blob/main/examples/ManualLifting.jsx) for example on this approach.
84
+
85
+ A demo of the example is attach below:
86
+
87
+ <img src="https://github.com/deflexable/react-native-dodge-keyboard/blob/main/screenshots/static.gif" width="260">
package/index.d.ts CHANGED
@@ -83,7 +83,7 @@ export interface DodgeKeyboardProps {
83
83
 
84
84
  }
85
85
 
86
- export default function DodgeKeyboard(
86
+ export function DodgeKeyboard(
87
87
  props: DodgeKeyboardProps
88
88
  ): React.ReactElement | null;
89
89
 
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { Children, cloneElement, createElement, forwardRef, isValidElement, memo, useEffect, useMemo, useRef, useState } from "react";
1
+ import { Children, cloneElement, createElement, forwardRef, isValidElement, memo, useEffect, useMemo, useRef, useState, useImperativeHandle } from "react";
2
2
  import { Animated, Dimensions, findNodeHandle, Keyboard, Platform, StyleSheet, UIManager, useAnimatedValue } from "react-native";
3
3
 
4
- export default function ({ children, offset = 10, disabled, onHandleDodging, disableTagCheck, checkIfElementIsFocused }) {
4
+ export const DodgeKeyboard = forwardRef(({ children, offset = 10, disabled, onHandleDodging, disableTagCheck, checkIfElementIsFocused }, ref) => {
5
5
  if (checkIfElementIsFocused !== undefined) {
6
6
  if (typeof checkIfElementIsFocused !== 'function')
7
7
  throw 'checkIfElementIsFocused should be a function';
@@ -97,7 +97,7 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
97
97
  if (!eventContext?.fromTimer && resizerTimer.current === undefined)
98
98
  resizerTimer.current = setTimeout(() => {
99
99
  doDodgeKeyboard.current(undefined, undefined, { fromTimer: true });
100
- }, 700);
100
+ }, 500);
101
101
  }
102
102
 
103
103
  const checkFocused = checkIfElementIsFocused || (r => r?.isFocused?.());
@@ -140,14 +140,14 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
140
140
  });
141
141
  }),
142
142
  new Promise(resolve => {
143
- inputObj.measure((x, y, width, height, pageX, pageY) => { // y is dynamic
143
+ UIManager.measure(findNodeHandle(inputObj), (x, y, width, height, pageX, pageY) => { // y is dynamic
144
144
  resolve({ py: pageY, layout: { x, y, width, height, pageX, pageY } });
145
145
  });
146
146
  }),
147
147
  new Promise((resolve, reject) => {
148
- inputObj.measureLayout(scrollRef, (l, t, width, height) => { // t is fixed
148
+ UIManager.measureLayout(findNodeHandle(inputObj), findNodeHandle(scrollRef), reject, (l, t, width, height) => { // t is fixed
149
149
  resolve({ t, h: height, relativeLayout: { left: l, top: t, width, height } });
150
- }, reject);
150
+ });
151
151
  })
152
152
  ]).then(([{ h: sh, py: sy, scrollLayout }, { py: y, layout }, { t, h, relativeLayout }]) => {
153
153
 
@@ -198,7 +198,7 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
198
198
  }
199
199
  }
200
200
  }
201
- } else {
201
+ } else if (!visible) {
202
202
  setCurrentPaddedScroller();
203
203
  clearPreviousDodge();
204
204
  }
@@ -224,7 +224,14 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
224
224
  useEffect(() => {
225
225
  if (currentPaddedScroller) {
226
226
  const ref = viewRefsMap.current[paddedId]?.scrollRef;
227
- tryPerformScroll(ref, paddedScroll, false);
227
+ if (Platform.OS === 'android') {
228
+ tryPerformScroll(ref, paddedScroll, false);
229
+ } else {
230
+ // this seem to be removing `the flash bang` on IOS
231
+ setTimeout(() => {
232
+ tryPerformScroll(ref, paddedScroll, false);
233
+ }, 1);
234
+ }
228
235
  }
229
236
  }, [currentPaddedScroller]);
230
237
 
@@ -232,6 +239,10 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
232
239
  doDodgeKeyboard.current();
233
240
  }, [offset, !disabled]);
234
241
 
242
+ useImperativeHandle(ref, () => ({
243
+ trigger: () => doDodgeKeyboard.current()
244
+ }), []);
245
+
235
246
  useEffect(() => {
236
247
  if (disabled) return;
237
248
  const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => doDodgeKeyboard.current(e));
@@ -322,7 +333,7 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
322
333
  ...inputNode.props,
323
334
  __dodging_keyboard: true,
324
335
  onFocus: (...args) => {
325
- doDodgeKeyboard.current();
336
+ doDodgeKeyboard.current(lastKeyboardEvent.current);
326
337
  return inputNode.props?.onFocus?.(...args);
327
338
  },
328
339
  onLayout: (...args) => {
@@ -381,7 +392,7 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
381
392
  },
382
393
  ...isStandalone ? {
383
394
  onFocus: (...args) => {
384
- doDodgeKeyboard.current();
395
+ doDodgeKeyboard.current(lastKeyboardEvent.current);
385
396
  return node.props?.onFocus?.(...args);
386
397
  }
387
398
  } : {},
@@ -424,7 +435,7 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
424
435
  {children}
425
436
  </ReactHijacker>
426
437
  );
427
- };
438
+ });
428
439
 
429
440
  const niceFunction = (func, message) => {
430
441
  return (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-dodge-keyboard",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "react-native-dodge-keyboard is a tiny library designed to flawlessly move your UI out of the way of the keyboard",
5
5
  "keywords": [
6
6
  "react-native",