All files / react-native-web/src/modules/useElementLayout index.js

67.65% Statements 23/34
80.77% Branches 21/26
55.56% Functions 5/9
67.65% Lines 23/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93                                16x   16x 16x     603x 594x 15x                                                 9x 9x               603x             603x   603x 458x 458x 458x           603x 438x 438x 429x 40x   389x     438x 436x 427x          
/**
 * Copyright (c) Nicolas Gallagher.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */
 
import type { ElementRef } from 'react';
import type { LayoutEvent } from '../../types';
 
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import useLayoutEffect from '../useLayoutEffect';
import UIManager from '../../exports/UIManager';
 
const DOM_LAYOUT_HANDLER_NAME = '__reactLayoutHandler';
 
let didWarn = !canUseDOM;
let resizeObserver = null;
 
function getResizeObserver(): ?ResizeObserver {
  if (canUseDOM && typeof window.ResizeObserver !== 'undefined') {
    if (resizeObserver == null) {
      resizeObserver = new window.ResizeObserver(function (entries) {
        entries.forEach((entry) => {
          const node = entry.target;
          const onLayout = node[DOM_LAYOUT_HANDLER_NAME];
          if (typeof onLayout === 'function') {
            // We still need to measure the view because browsers don't yet provide
            // border-box dimensions in the entry
            UIManager.measure(node, (x, y, width, height, left, top) => {
              const event: LayoutEvent = {
                // $FlowFixMe
                nativeEvent: {
                  layout: { x, y, width, height, left, top }
                },
                timeStamp: Date.now()
              };
              Object.defineProperty(event.nativeEvent, 'target', {
                enumerable: true,
                get: () => entry.target
              });
              onLayout(event);
            });
          }
        });
      });
    }
  } else Eif (!didWarn) {
    Iif (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
      console.warn(
        'onLayout relies on ResizeObserver which is not supported by your browser. ' +
          'Please include a polyfill, e.g., https://github.com/que-etc/resize-observer-polyfill.'
      );
      didWarn = true;
    }
  }
  return resizeObserver;
}
 
export default function useElementLayout(
  ref: ElementRef<any>,
  onLayout?: ?(e: LayoutEvent) => void
) {
  const observer = getResizeObserver();
 
  useLayoutEffect(() => {
    const node = ref.current;
    Eif (node != null) {
      node[DOM_LAYOUT_HANDLER_NAME] = onLayout;
    }
  }, [ref, onLayout]);
 
  // Observing is done in a separate effect to avoid this effect running
  // when 'onLayout' changes.
  useLayoutEffect(() => {
    const node = ref.current;
    if (node != null && observer != null) {
      if (typeof node[DOM_LAYOUT_HANDLER_NAME] === 'function') {
        observer.observe(node);
      } else {
        observer.unobserve(node);
      }
    }
    return () => {
      if (node != null && observer != null) {
        observer.unobserve(node);
      }
    };
  }, [ref, observer]);
}