Nessuna descrizione

NativeSafeAreaView.web.tsx 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import * as React from 'react';
  2. import { ViewStyle, View } from 'react-native';
  3. import { InsetChangeNativeCallback } from './SafeArea.types';
  4. interface NativeSafeAreaViewProps {
  5. children?: React.ReactNode;
  6. style: ViewStyle;
  7. onInsetsChange: InsetChangeNativeCallback;
  8. }
  9. enum CSSTransitions {
  10. WebkitTransition = 'webkitTransitionEnd',
  11. Transition = 'transitionEnd',
  12. MozTransition = 'transitionend',
  13. MSTransition = 'msTransitionEnd',
  14. OTransition = 'oTransitionEnd',
  15. }
  16. export default function NativeSafeAreaView({
  17. children,
  18. style,
  19. onInsetsChange,
  20. }: NativeSafeAreaViewProps) {
  21. const element = createContextElement();
  22. document.body.appendChild(element);
  23. const onEnd = () => {
  24. const {
  25. paddingTop,
  26. paddingBottom,
  27. paddingLeft,
  28. paddingRight,
  29. } = getComputedStyle(element);
  30. const insets = {
  31. top: paddingTop ? parseInt(paddingTop, 10) : 0,
  32. bottom: paddingBottom ? parseInt(paddingBottom, 10) : 0,
  33. left: paddingLeft ? parseInt(paddingLeft, 10) : 0,
  34. right: paddingRight ? parseInt(paddingRight, 10) : 0,
  35. };
  36. console.log('onEnd');
  37. // @ts-ignore: missing properties
  38. onInsetsChange({ nativeEvent: { insets } });
  39. };
  40. React.useEffect(() => {
  41. console.log(
  42. 'SUPPORTED_TRANSITION_EVENT',
  43. SUPPORTED_TRANSITION_EVENT,
  44. SUPPORTED_ENV,
  45. );
  46. element.addEventListener(SUPPORTED_TRANSITION_EVENT, onEnd);
  47. onEnd();
  48. return () => {
  49. document.body.removeChild(element);
  50. element.removeEventListener(SUPPORTED_TRANSITION_EVENT, onEnd);
  51. };
  52. }, [onInsetsChange]);
  53. return <View style={style}>{children}</View>;
  54. }
  55. const SUPPORTED_TRANSITION_EVENT: string = (() => {
  56. const element = document.createElement('invalidtype');
  57. for (const key in CSSTransitions) {
  58. if (element.style[key] !== undefined) {
  59. return CSSTransitions[key];
  60. }
  61. }
  62. return CSSTransitions.Transition;
  63. })();
  64. const SUPPORTED_ENV: 'constant' | 'env' = (() => {
  65. // @ts-ignore: Property 'CSS' does not exist on type 'Window'.ts(2339)
  66. const { CSS } = window;
  67. if (
  68. CSS &&
  69. CSS.supports &&
  70. CSS.supports('top: constant(safe-area-inset-top)')
  71. ) {
  72. return 'constant';
  73. }
  74. return 'env';
  75. })();
  76. function getInset(side: string): string {
  77. return `${SUPPORTED_ENV}(safe-area-inset-${side})`;
  78. }
  79. function createContextElement(): HTMLElement {
  80. const element = document.createElement('div');
  81. const { style } = element;
  82. style.position = 'fixed';
  83. style.left = '0';
  84. style.top = '0';
  85. style.width = '0';
  86. style.height = '0';
  87. style.zIndex = '-1';
  88. style.overflow = 'hidden';
  89. style.visibility = 'hidden';
  90. // Bacon: Anything faster than this and the callback will be invoked too early with the wrong insets
  91. style.transitionDuration = '0.05s';
  92. style.transitionProperty = 'padding';
  93. style.transitionDelay = '0s';
  94. style.paddingTop = getInset('top');
  95. style.paddingBottom = getInset('bottom');
  96. style.paddingLeft = getInset('left');
  97. style.paddingRight = getInset('right');
  98. return element;
  99. }