react-native-dodge-keyboard 1.0.1 → 1.0.3

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.
Files changed (4) hide show
  1. package/TODO +1 -0
  2. package/index.d.ts +10 -1
  3. package/index.js +285 -192
  4. package/package.json +1 -1
package/TODO ADDED
@@ -0,0 +1 @@
1
+ keyboard not dodging in state changes
package/index.d.ts CHANGED
@@ -102,6 +102,15 @@ interface ReactHijackerProps {
102
102
  }
103
103
 
104
104
  export function ReactHijacker(props: ReactHijackerProps): React.ReactElement | null;
105
+ export function __HijackNode(props: { children: () => React.ReactElement | null }): React.ReactElement | null;
106
+
107
+ export function createHijackedElement(element?: React.ReactElement | null): { __element: React.ReactElement | null };
105
108
 
106
109
  export function isDodgeScrollable(element: React.ReactNode, disableTagCheck?: boolean): boolean;
107
- export function isDodgeInput(element: React.ReactNode, disableTagCheck?: boolean): boolean;
110
+ export function isDodgeInput(element: React.ReactNode, disableTagCheck?: boolean): boolean;
111
+
112
+ interface KeyboardPlaceholderProps {
113
+ doHeight: (keyboardheight: number) => number;
114
+ }
115
+
116
+ export function KeyboardPlaceholderView(props: KeyboardPlaceholderProps): React.ReactElement | null;
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Children, cloneElement, createElement, forwardRef, isValidElement, memo, useEffect, useMemo, useRef, useState } from "react";
2
- import { Dimensions, findNodeHandle, Keyboard, StyleSheet, UIManager } from "react-native";
2
+ import { Animated, Dimensions, findNodeHandle, Keyboard, Platform, StyleSheet, UIManager, useAnimatedValue } from "react-native";
3
3
 
4
4
  export default function ({ children, offset = 10, disabled, onHandleDodging, disableTagCheck, checkIfElementIsFocused }) {
5
5
  if (checkIfElementIsFocused !== undefined) {
@@ -24,9 +24,9 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
24
24
  * @type {import("react").RefObject<{[key: string]: { __is_standalone: boolean, _standalone_props: { dodge_keyboard_offset?: number, dodge_keyboard_lift?: boolean }, scrollRef: import("react-native").ScrollView, inputRef: {[key: string]: { ref: import("react-native").TextInput, props: { dodge_keyboard_offset?: number, dodge_keyboard_lift?: boolean } }} }}>}
25
25
  */
26
26
  const viewRefsMap = useRef({});
27
- const isKeyboardVisible = useRef();
28
27
  const doDodgeKeyboard = useRef();
29
28
  const previousLift = useRef();
29
+ const wasVisible = useRef();
30
30
 
31
31
  const clearPreviousDodge = (scrollId) => {
32
32
  if (previousLift.current && previousLift.current !== scrollId) {
@@ -36,14 +36,26 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
36
36
  }
37
37
  }
38
38
 
39
- doDodgeKeyboard.current = () => {
39
+ /**
40
+ * @param {import('react-native').KeyboardEvent | undefined} event
41
+ * @param {boolean} visible
42
+ */
43
+ doDodgeKeyboard.current = (event, visible) => {
44
+ if (typeof visible !== 'boolean') {
45
+ if (typeof wasVisible.current === 'boolean') {
46
+ visible = wasVisible.current;
47
+ } else return;
48
+ }
49
+
50
+ wasVisible.current = visible;
51
+
40
52
  try {
41
- const keyboardInfo = Keyboard.metrics();
53
+ const keyboardInfo = event?.endCoordinates || Keyboard.metrics();
42
54
  const { width: windowWidth, height: windowHeight } = Dimensions.get('window');
43
55
 
44
- console.log('doDodgeKeyboard');
56
+ // console.log('doDodgeKeyboard');
45
57
  if (
46
- isKeyboardVisible.current &&
58
+ visible &&
47
59
  keyboardInfo &&
48
60
  !disabled &&
49
61
  (keyboardInfo.width === windowWidth ||
@@ -97,11 +109,11 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
97
109
  const scrollLift = Math.max(0, (sy + sh + (thisOffset >= 0 ? thisOffset : 0)) - keyboardInfo.screenY);
98
110
  const newScrollY = Math.min(requiredScrollY, t);
99
111
 
100
- console.log('scrolling-to:', requiredScrollY, ' scrollLift:', scrollLift);
112
+ // console.log('scrolling-to:', requiredScrollY, ' scrollLift:', scrollLift);
101
113
  if (scrollLift) {
102
114
  setCurrentPaddedScroller([scrollId, scrollLift, newScrollY]);
103
115
  } else {
104
- scrollRef.scrollTo({ y: newScrollY, animated: true });
116
+ tryPerformScroll(scrollRef, newScrollY, true);
105
117
  setCurrentPaddedScroller();
106
118
  }
107
119
  }
@@ -124,20 +136,24 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
124
136
  }
125
137
  }
126
138
 
139
+ const tryPerformScroll = (ref, y, animated = true) => {
140
+ if (!ref) return;
141
+
142
+ if (ref.scrollTo) {
143
+ ref.scrollTo?.({ y, animated });
144
+ } else if (ref.scrollToOffset) {
145
+ ref.scrollToOffset?.({ offset: y, animated });
146
+ } else {
147
+ ref.getScrollResponder?.()?.scrollTo?.({ y, animated });
148
+ }
149
+ }
150
+
127
151
  const [paddedId, paddedSize, paddedScroll] = currentPaddedScroller || [];
128
152
 
129
153
  useEffect(() => {
130
154
  if (currentPaddedScroller) {
131
155
  const ref = viewRefsMap.current[paddedId]?.scrollRef;
132
- if (ref) {
133
- if (ref.scrollTo) {
134
- ref.scrollTo?.({ y: paddedScroll, animated: true });
135
- } else if (ref.scrollToOffset) {
136
- ref.scrollToOffset?.({ offset: paddedScroll, animated: true });
137
- } else {
138
- ref.getScrollResponder?.()?.scrollTo?.({ y: paddedScroll, animated: true });
139
- }
140
- }
156
+ tryPerformScroll(ref, paddedScroll, false);
141
157
  }
142
158
  }, [currentPaddedScroller]);
143
159
 
@@ -147,19 +163,15 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
147
163
 
148
164
  useEffect(() => {
149
165
  if (disabled) return;
150
- const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => {
151
- doDodgeKeyboard.current();
152
- });
153
-
154
- const showListener = Keyboard.addListener('keyboardDidShow', e => {
155
- isKeyboardVisible.current = true;
156
- doDodgeKeyboard.current();
157
- });
158
-
159
- const hiddenListener = Keyboard.addListener('keyboardDidHide', e => {
160
- isKeyboardVisible.current = false;
161
- doDodgeKeyboard.current();
162
- });
166
+ const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => doDodgeKeyboard.current(e));
167
+ const showListener = Keyboard.addListener(
168
+ Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow',
169
+ e => doDodgeKeyboard.current(e, true)
170
+ );
171
+ const hiddenListener = Keyboard.addListener(
172
+ Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide',
173
+ e => doDodgeKeyboard.current(e, false)
174
+ );
163
175
 
164
176
  return () => {
165
177
  frameListener.remove();
@@ -168,135 +180,158 @@ export default function ({ children, offset = 10, disabled, onHandleDodging, dis
168
180
  }
169
181
  }, [!disabled]);
170
182
 
171
- return (
172
- <ReactHijacker
173
- doHijack={(node, path) => {
174
- if (node?.props?.['dodge_keyboard_scan_off']) return { element: node };
175
-
176
- const isStandalone = isDodgeInput(node);
177
-
178
- if (isStandalone || isDodgeScrollable(node, disableTagCheck)) {
179
- const scrollId = path.join('=>');
180
- const initNode = () => {
181
- if (!viewRefsMap.current[scrollId])
182
- viewRefsMap.current[scrollId] = { inputRef: {} };
183
-
184
- if (isStandalone) {
185
- viewRefsMap.current[scrollId].__is_standalone = true;
186
- viewRefsMap.current[scrollId]._standalone_props = {
187
- dodge_keyboard_offset: node.props?.dodge_keyboard_offset,
188
- dodge_keyboard_lift: node.props?.dodge_keyboard_lift
189
- };
190
- }
191
- }
192
- const shouldPad = scrollId === paddedId;
193
- const contentStyle = shouldPad && StyleSheet.flatten(node.props?.contentContainerStyle);
194
- const rootRenderItem = node.prop?.renderItem;
195
- const rootKeyExtractor = node.prop?.keyExtractor;
196
- const hasInternalList = !isStandalone && (typeof rootRenderItem === 'function' && !node.props?.children);
197
-
198
- const injectChild = (children, childPath) =>
199
- ReactHijacker({
200
- children,
201
- path: childPath,
202
- doHijack: (inputNode, path) => {
203
- if (isDodgeInput(inputNode, disableTagCheck)) {
204
- const inputId = path.join('=>');
205
- const initInputNode = () => {
206
- initNode();
207
- if (!viewRefsMap.current[scrollId].inputRef[inputId])
208
- viewRefsMap.current[scrollId].inputRef[inputId] = {};
209
- viewRefsMap.current[scrollId].inputRef[inputId].props = {
210
- dodge_keyboard_offset: inputNode.props?.dodge_keyboard_offset,
211
- dodge_keyboard_lift: inputNode.props?.dodge_keyboard_lift
212
- };
213
- }
183
+ const nodeIdIte = useRef(0);
214
184
 
215
- initInputNode();
216
-
217
- return {
218
- props: {
219
- ...inputNode.props,
220
- onFocus: (...args) => {
221
- doDodgeKeyboard.current();
222
- return inputNode.props?.onFocus?.(...args);
223
- },
224
- onLayout: (...args) => {
225
- doDodgeKeyboard.current();
226
- return inputNode.props?.onLayout?.(...args);
227
- },
228
- ref: r => {
229
- if (r) {
230
- initInputNode();
231
-
232
- viewRefsMap.current[scrollId].inputRef[inputId].ref = r;
233
- } else if (viewRefsMap.current[scrollId]?.inputRef?.[inputId]) {
234
- delete viewRefsMap.current[scrollId].inputRef[inputId];
235
- }
185
+ const onHijackNode = node => {
186
+ if (node?.props?.dodge_keyboard_scan_off || node?.props?.__dodging_keyboard) return;
236
187
 
237
- const thatRef = inputNode.props?.ref;
238
- if (typeof thatRef === 'function') {
239
- thatRef(r);
240
- } else if (thatRef) thatRef.current = r;
241
- }
242
- }
243
- };
244
- }
188
+ const isStandalone = isDodgeInput(node);
189
+ if (!isStandalone && !isDodgeScrollable(node, disableTagCheck)) return;
190
+
191
+ const renderer = () => {
192
+ const scrollId = useMemo(() => `${++nodeIdIte.current}`, []);
193
+
194
+ const initNode = () => {
195
+ if (!viewRefsMap.current[scrollId])
196
+ viewRefsMap.current[scrollId] = { inputRef: {} };
197
+
198
+ if (isStandalone) {
199
+ viewRefsMap.current[scrollId].__is_standalone = true;
200
+ viewRefsMap.current[scrollId]._standalone_props = {
201
+ dodge_keyboard_offset: node.props?.dodge_keyboard_offset,
202
+ dodge_keyboard_lift: node.props?.dodge_keyboard_lift
203
+ };
204
+ }
205
+ }
206
+ const shouldPad = !isStandalone && scrollId === paddedId;
207
+ const contentStyle = shouldPad && StyleSheet.flatten(node.props?.contentContainerStyle);
208
+ const rootRenderItem = node.props?.renderItem;
209
+ const hasInternalList = !isStandalone && (typeof rootRenderItem === 'function' && !node.props?.children);
210
+
211
+ const doRefCleanup = () => {
212
+ if (
213
+ viewRefsMap.current[scrollId]?.scrollRef ||
214
+ Object.keys(viewRefsMap.current[scrollId]?.inputRef || {}).length
215
+ ) return;
216
+ delete viewRefsMap.current[scrollId];
217
+ }
218
+
219
+ const injectChild = (children, childPath) =>
220
+ ReactHijacker({
221
+ children,
222
+ path: childPath,
223
+ doHijack: inputNode => {
224
+ if (node?.props?.__dodging_keyboard) return;
225
+
226
+ if (!isDodgeInput(inputNode, disableTagCheck)) return;
227
+
228
+ const inputRenderer = () => {
229
+ const inputId = useMemo(() => `${++nodeIdIte.current}`, []);
230
+ const initInputNode = () => {
231
+ initNode();
232
+ if (!viewRefsMap.current[scrollId].inputRef[inputId])
233
+ viewRefsMap.current[scrollId].inputRef[inputId] = {};
234
+ viewRefsMap.current[scrollId].inputRef[inputId].props = {
235
+ dodge_keyboard_offset: inputNode.props?.dodge_keyboard_offset,
236
+ dodge_keyboard_lift: inputNode.props?.dodge_keyboard_lift
237
+ };
245
238
  }
246
- });
247
-
248
- return {
249
- props: {
250
- ...node.props,
251
- ...shouldPad ? {
252
- contentContainerStyle: {
253
- ...contentStyle,
254
- paddingBottom: paddedSize + (isNumber(contentStyle?.paddingBottom) ? contentStyle.paddingBottom : 0)
255
- }
256
- } : {},
257
- ref: r => {
258
- if (r) {
259
- initNode();
260
- viewRefsMap.current[scrollId].scrollRef = r;
261
- } else if (viewRefsMap.current[scrollId]) {
262
- delete viewRefsMap.current[scrollId];
263
- }
264
239
 
265
- const thatRef = node.props?.ref;
266
- if (typeof thatRef === 'function') {
267
- thatRef(r);
268
- } else if (thatRef) thatRef.current = r;
269
- },
270
- ...isStandalone ? {
240
+ initInputNode();
241
+
242
+ const newProps = {
243
+ ...inputNode.props,
244
+ __dodging_keyboard: true,
271
245
  onFocus: (...args) => {
272
246
  doDodgeKeyboard.current();
273
- return node.props?.onFocus?.(...args);
274
- }
275
- } : {},
276
- onLayout: (...args) => {
277
- doDodgeKeyboard.current();
278
- return node.props?.onLayout?.(...args);
279
- },
280
- ...isStandalone ? {} :
281
- hasInternalList ? {
282
- renderItem: (...args) => {
283
- const { item, index } = args[0] || {};
284
-
285
- return injectChild(
286
- rootRenderItem(...args),
287
- [
288
- ...path,
289
- index,
290
- ...typeof rootKeyExtractor === 'function' ?
291
- [rootKeyExtractor?.(item, index)] : []
292
- ]
293
- );
247
+ return inputNode.props?.onFocus?.(...args);
248
+ },
249
+ onLayout: (...args) => {
250
+ doDodgeKeyboard.current();
251
+ return inputNode.props?.onLayout?.(...args);
252
+ },
253
+ ref: r => {
254
+ if (r) {
255
+ initInputNode();
256
+
257
+ viewRefsMap.current[scrollId].inputRef[inputId].ref = r;
258
+ } else if (viewRefsMap.current[scrollId]?.inputRef?.[inputId]) {
259
+ delete viewRefsMap.current[scrollId].inputRef[inputId];
260
+ doRefCleanup();
294
261
  }
295
- } : { children: injectChild(node.props?.children, path) }
262
+
263
+ const thatRef = inputNode.props?.ref;
264
+ if (typeof thatRef === 'function') {
265
+ thatRef(r);
266
+ } else if (thatRef) thatRef.current = r;
267
+ }
268
+ };
269
+
270
+ return cloneElement(inputNode, newProps);
296
271
  }
297
- };
298
- }
299
- }}>
272
+
273
+ return createHijackedElement(
274
+ <__HijackNode>
275
+ {inputRenderer}
276
+ </__HijackNode>
277
+ );
278
+ }
279
+ });
280
+
281
+ const newProps = {
282
+ ...node.props,
283
+ __dodging_keyboard: true,
284
+ ...shouldPad ? {
285
+ contentContainerStyle: {
286
+ ...contentStyle,
287
+ paddingBottom: paddedSize + (isNumber(contentStyle?.paddingBottom) ? contentStyle.paddingBottom : 0)
288
+ }
289
+ } : {},
290
+ ref: r => {
291
+ if (r) {
292
+ initNode();
293
+ viewRefsMap.current[scrollId].scrollRef = r;
294
+ } else if (viewRefsMap.current[scrollId]) {
295
+ viewRefsMap.current[scrollId].scrollRef = undefined;
296
+ doRefCleanup();
297
+ }
298
+
299
+ const thatRef = node.props?.ref;
300
+ if (typeof thatRef === 'function') {
301
+ thatRef(r);
302
+ } else if (thatRef) thatRef.current = r;
303
+ },
304
+ ...isStandalone ? {
305
+ onFocus: (...args) => {
306
+ doDodgeKeyboard.current();
307
+ return node.props?.onFocus?.(...args);
308
+ }
309
+ } : {},
310
+ onLayout: (...args) => {
311
+ doDodgeKeyboard.current();
312
+ return node.props?.onLayout?.(...args);
313
+ },
314
+ ...isStandalone ? {} :
315
+ hasInternalList ? {
316
+ renderItem: (...args) => {
317
+ return injectChild(rootRenderItem(...args));
318
+ }
319
+ } : { children: injectChild(node.props?.children) }
320
+ };
321
+
322
+ return cloneElement(node, newProps);
323
+ }
324
+
325
+ return createHijackedElement(
326
+ <__HijackNode>
327
+ {renderer}
328
+ </__HijackNode>
329
+ );
330
+ };
331
+
332
+ return (
333
+ <ReactHijacker
334
+ doHijack={onHijackNode}>
300
335
  {children}
301
336
  </ReactHijacker>
302
337
  );
@@ -319,61 +354,43 @@ const REACT_SYMBOLS = {
319
354
  memo: Symbol.for('react.memo')
320
355
  };
321
356
 
322
- export function ReactHijacker({ children, doHijack, path }) {
323
- const renderRefs = useMemo(() => new Map(), []);
324
-
357
+ export function ReactHijacker({ children, doHijack, enableLocator }) {
325
358
  const instantDoHijack = useRef();
326
359
  instantDoHijack.current = doHijack;
327
360
 
328
- const injectIntoTree = (node, path = [], wasArray) => {
361
+ const injectIntoTree = (node, path) => {
329
362
  if (!node) return node;
330
363
  if (Array.isArray(node)) {
331
- return Children.map(node, (v, i) => injectIntoTree(v, [...path, i], true));
364
+ return Children.map(node, (v, i) => injectIntoTree(v, path && [...path, i]));
332
365
  }
333
366
  if (!isValidElement(node)) return node;
334
367
 
335
- path = [...path, ...wasArray ? [] : [0], getNodeId(node)];
368
+ if (path) path = [...path, getNodeId(node)];
336
369
 
337
370
  let thisObj;
338
- if (thisObj = instantDoHijack.current?.(node, path)) {
339
- const { element, props } = thisObj;
340
-
341
- if (Object.hasOwn(thisObj, 'element')) return element;
342
- if (props) return cloneElement(node, props);
343
- return node;
371
+ if (Object.hasOwn((thisObj = instantDoHijack.current?.(node, path)) || {}, '__element')) {
372
+ return thisObj.__element;
344
373
  }
345
374
 
346
375
  if (!isHostElement(node)) {
347
376
  const wrapNodeType = (nodeType, pathway, pathKey) => {
348
- pathway = [...pathway, getNodeId(undefined, nodeType, pathKey)];
349
- const path_id = pathway.join(',');
350
- let renderRefStore = renderRefs.get(nodeType);
351
-
352
- if (renderRefStore?.[path_id]) return renderRefStore[path_id];
377
+ if (pathway) pathway = [...pathway, getNodeId(undefined, nodeType, pathKey)];
353
378
 
354
379
  // if (doLogging) console.log('wrapNodeType path:', pathway, ' node:', nodeType);
355
380
  const render = (renderedNode) => {
356
381
  // if (doLogging) console.log('deep path:', pathway, ' node:', renderedNode);
357
- return injectIntoTree(renderedNode, pathway);
382
+ return injectIntoTree(renderedNode, pathway && [...pathway, 0]);
358
383
  }
359
384
 
360
- let newType;
361
-
362
385
  if (typeof nodeType === 'function') { // check self closed tag
363
- newType = hijackRender(nodeType, render);
386
+ return hijackRender(nodeType, render);
364
387
  } else if (nodeType?.$$typeof === REACT_SYMBOLS.forwardRef) {
365
- newType = forwardRef(hijackRender(nodeType.render, render));
388
+ return forwardRef(hijackRender(nodeType.render, render));
366
389
  } else if (nodeType?.$$typeof === REACT_SYMBOLS.memo) {
367
- newType = memo(wrapNodeType(nodeType.type, pathway), nodeType.compare);
390
+ const newType = memo(wrapNodeType(nodeType.type, pathway), nodeType.compare);
368
391
  newType.displayName = nodeType.displayName || nodeType.name;
369
- }
370
-
371
- if (newType) {
372
- if (!renderRefStore) renderRefs.set(nodeType, renderRefStore = {});
373
- renderRefStore[path_id] = newType;
374
392
  return newType;
375
393
  }
376
-
377
394
  return nodeType;
378
395
  }
379
396
 
@@ -383,15 +400,24 @@ export function ReactHijacker({ children, doHijack, path }) {
383
400
  node.type?.$$typeof === REACT_SYMBOLS.memo // check memo
384
401
  ) {
385
402
  // if (doLogging) console.log('doLog path:', path, ' node:', node);
386
- const injectedType = wrapNodeType(node.type, path.slice(0, -1), node.key);
387
- return createElement(
388
- injectedType,
389
- {
390
- ...node.props,
391
- key: node.key,
392
- // ...isForwardRef ? { ref: node.ref } : {}
393
- },
394
- node.props?.children
403
+ return (
404
+ <__HijackNodePath>
405
+ {() => {
406
+ const hijackType = useMemo(() =>
407
+ wrapNodeType(node.type, path && path.slice(0, -1), node.key),
408
+ [node.type]
409
+ );
410
+
411
+ return createElement(
412
+ hijackType,
413
+ {
414
+ ...node.props,
415
+ key: node.key
416
+ },
417
+ node.props?.children
418
+ );
419
+ }}
420
+ </__HijackNodePath>
395
421
  );
396
422
  }
397
423
  }
@@ -399,15 +425,24 @@ export function ReactHijacker({ children, doHijack, path }) {
399
425
  const children = node.props?.children;
400
426
  if (children)
401
427
  return cloneElement(node, {
402
- children: injectIntoTree(children, path)
428
+ children: injectIntoTree(children, path && [...path, 0])
403
429
  });
404
430
 
405
431
  return node;
406
432
  };
407
433
 
408
- return injectIntoTree(children, path);
434
+ return injectIntoTree(children, enableLocator ? [] : undefined);
409
435
  };
410
436
 
437
+ export const createHijackedElement = (element) => ({ __element: element });
438
+ export function __HijackNode({ children }) {
439
+ return children?.();
440
+ }
441
+
442
+ function __HijackNodePath({ children }) {
443
+ return children?.();
444
+ }
445
+
411
446
  const hijackRender = (type, doHijack) =>
412
447
  new Proxy(type, {
413
448
  apply(target, thisArg, args) {
@@ -481,4 +516,62 @@ export const isDodgeInput = (element, disableTagCheck) => {
481
516
 
482
517
  return inputTypes.includes(element.type?.displayName)
483
518
  || inputTypes.includes(element.type?.name);
484
- };
519
+ };
520
+
521
+ export const KeyboardPlaceholderView = ({ doHeight }) => {
522
+ const height = useAnimatedValue(0);
523
+
524
+ const instantDoHeight = useRef();
525
+ instantDoHeight.current = doHeight;
526
+
527
+ useEffect(() => {
528
+ let wasVisible;
529
+ /**
530
+ * @param {import('react-native').KeyboardEvent} event
531
+ * @param {boolean} visible
532
+ */
533
+ const updateKeyboardHeight = (event, visible) => {
534
+ if (typeof visible !== 'boolean') {
535
+ if (typeof wasVisible === 'boolean') {
536
+ visible = wasVisible;
537
+ } else return;
538
+ }
539
+
540
+ wasVisible = visible;
541
+
542
+ const { endCoordinates, isEventFromThisApp, duration } = event;
543
+ if (Platform.OS === 'ios' && !isEventFromThisApp) return;
544
+
545
+ const kh = visible ? endCoordinates.height : 0;
546
+ const newHeight = Math.max(0, instantDoHeight.current ? instantDoHeight.current(kh) : kh);
547
+ const newDuration = (Math.abs(height._value - newHeight) * duration) / endCoordinates.height;
548
+
549
+ Animated.timing(height, {
550
+ duration: newDuration,
551
+ toValue: newHeight,
552
+ useNativeDriver: false
553
+ }).start();
554
+ }
555
+
556
+ const initialMetric = Keyboard.metrics();
557
+ if (initialMetric) updateKeyboardHeight(initialMetric, true);
558
+
559
+ const frameListener = Keyboard.addListener('keyboardDidChangeFrame', e => updateKeyboardHeight(e));
560
+ const showListener = Keyboard.addListener(
561
+ Platform.OS === 'android' ? 'keyboardDidShow' : 'keyboardWillShow',
562
+ e => updateKeyboardHeight(e, true)
563
+ );
564
+ const hiddenListener = Keyboard.addListener(
565
+ Platform.OS === 'android' ? 'keyboardDidHide' : 'keyboardWillHide',
566
+ e => updateKeyboardHeight(e, false)
567
+ );
568
+
569
+ return () => {
570
+ frameListener.remove();
571
+ showListener.remove();
572
+ hiddenListener.remove();
573
+ }
574
+ }, []);
575
+
576
+ return <Animated.View style={{ height }} />;
577
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-dodge-keyboard",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
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",