You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JitsiKeyboardAvoidingView.js 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // @flow
  2. import { useHeaderHeight } from '@react-navigation/elements';
  3. import React, { useCallback, useEffect, useState } from 'react';
  4. import {
  5. Keyboard,
  6. KeyboardAvoidingView,
  7. Platform,
  8. StatusBar
  9. } from 'react-native';
  10. import { useSafeAreaInsets } from 'react-native-safe-area-context';
  11. import { StyleType } from '../../styles';
  12. type Props = {
  13. /**
  14. * The children component(s) of the Modal, to be rendered.
  15. */
  16. children: React$Node,
  17. /**
  18. * Additional style to be appended to the KeyboardAvoidingView content container.
  19. */
  20. contentContainerStyle?: StyleType,
  21. /**
  22. * Disable forced keyboard dismiss?
  23. */
  24. disableForcedKeyboardDismiss?: boolean,
  25. /**
  26. * Is a text input rendered at the bottom of the screen?
  27. */
  28. hasBottomTextInput: boolean,
  29. /**
  30. * Is the screen rendering a tab navigator?
  31. */
  32. hasTabNavigator: boolean,
  33. /**
  34. * Additional style to be appended to the KeyboardAvoidingView.
  35. */
  36. style?: StyleType
  37. }
  38. const JitsiKeyboardAvoidingView = (
  39. {
  40. children,
  41. contentContainerStyle,
  42. hasTabNavigator,
  43. hasBottomTextInput,
  44. disableForcedKeyboardDismiss,
  45. style
  46. }: Props) => {
  47. const headerHeight = useHeaderHeight();
  48. const insets = useSafeAreaInsets();
  49. const [ bottomPadding, setBottomPadding ] = useState(insets.bottom);
  50. useEffect(() => {
  51. // This useEffect is needed because insets are undefined at first for some reason
  52. // https://github.com/th3rdwave/react-native-safe-area-context/issues/54
  53. setBottomPadding(insets.bottom);
  54. }, [ insets.bottom ]);
  55. const tabNavigatorPadding
  56. = hasTabNavigator ? headerHeight : 0;
  57. const noNotchDevicePadding = bottomPadding || 10;
  58. const iosVerticalOffset
  59. = headerHeight + noNotchDevicePadding + tabNavigatorPadding;
  60. const androidVerticalOffset = hasBottomTextInput
  61. ? headerHeight + StatusBar.currentHeight : headerHeight;
  62. // Tells the view what to do with taps
  63. const shouldSetResponse = useCallback(() => !disableForcedKeyboardDismiss);
  64. const onRelease = useCallback(() => Keyboard.dismiss());
  65. return (
  66. <KeyboardAvoidingView
  67. behavior = { Platform.OS === 'ios' ? 'padding' : 'height' }
  68. contentContainerStyle = { contentContainerStyle }
  69. enabled = { true }
  70. keyboardVerticalOffset = {
  71. Platform.OS === 'ios'
  72. ? iosVerticalOffset
  73. : androidVerticalOffset
  74. }
  75. onResponderRelease = { onRelease }
  76. onStartShouldSetResponder = { shouldSetResponse }
  77. style = { style }>
  78. { children }
  79. </KeyboardAvoidingView>
  80. );
  81. };
  82. export default JitsiKeyboardAvoidingView;