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.

KeyboardAvoider.tsx 1.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import React, { useEffect, useState } from 'react';
  2. import { isIosMobileBrowser } from '../../../base/environment/utils';
  3. /**
  4. * Component that renders an element to lift the chat input above the Safari keyboard,
  5. * computing the appropriate height comparisons based on the {@code visualViewport}.
  6. *
  7. * @returns {ReactElement}
  8. */
  9. function KeyboardAvoider() {
  10. if (!isIosMobileBrowser()) {
  11. return null;
  12. }
  13. const [ elementHeight, setElementHeight ] = useState(0);
  14. const [ storedHeight, setStoredHeight ] = useState(window.innerHeight);
  15. /**
  16. * Handles the resizing of the visual viewport in order to compute
  17. * the {@code KeyboardAvoider}'s height.
  18. *
  19. * @returns {void}
  20. */
  21. function handleViewportResize() {
  22. const { innerWidth, visualViewport } = window;
  23. const { width, height } = visualViewport ?? {};
  24. // Compare the widths to make sure the {@code visualViewport} didn't resize due to zooming.
  25. if (width === innerWidth) {
  26. if (Number(height) < storedHeight) {
  27. setElementHeight(storedHeight - Number(height));
  28. } else {
  29. setElementHeight(0);
  30. }
  31. setStoredHeight(Number(height));
  32. }
  33. }
  34. useEffect(() => {
  35. // Call the handler in case the keyboard is open when the {@code KeyboardAvoider} is mounted.
  36. handleViewportResize();
  37. window.visualViewport?.addEventListener('resize', handleViewportResize);
  38. return () => {
  39. window.visualViewport?.removeEventListener('resize', handleViewportResize);
  40. };
  41. }, []);
  42. return <div style = {{ height: `${elementHeight}px` }} />;
  43. }
  44. export default KeyboardAvoider;