addon/utils/scroll-helpers.js
function calculateScrollDistribution(deltaX, deltaY, element, container, accumulator = []) {
  const scrollInformation = {
    element,
    scrollLeft: 0,
    scrollTop: 0
  };
  const scrollLeftMax = element.scrollWidth - element.clientWidth;
  const scrollTopMax = element.scrollHeight - element.clientHeight;

  const availableScroll = {
    deltaXNegative: -element.scrollLeft,
    deltaXPositive: scrollLeftMax - element.scrollLeft,
    deltaYNegative: -element.scrollTop,
    deltaYPositive: scrollTopMax - element.scrollTop
  };

  const elementStyle = window.getComputedStyle(element);

  if (elementStyle.overflowX !== 'hidden') {
    // The `deltaX` can be larger than the available scroll for the element, thus overshooting.
    // The result of that is that it scrolls the element as far as possible. We don't need to
    // calculate exactly because we reduce the amount of desired scroll for the
    // parent elements by the correct amount below.
    scrollInformation.scrollLeft = element.scrollLeft + deltaX;
    if (deltaX > availableScroll.deltaXPositive) {
      deltaX = deltaX - availableScroll.deltaXPositive;
    } else if (deltaX < availableScroll.deltaXNegative) {
      deltaX = deltaX - availableScroll.deltaXNegative;
    } else {
      deltaX = 0;
    }
  }

  if (elementStyle.overflowY !== 'hidden') {
    scrollInformation.scrollTop = element.scrollTop + deltaY;
    if (deltaY > availableScroll.deltaYPositive) {
      deltaY = deltaY - availableScroll.deltaYPositive;
    } else if (deltaY < availableScroll.deltaYNegative) {
      deltaY = deltaY - availableScroll.deltaYNegative;
    } else {
      deltaY = 0;
    }
  }

  if (element !== container && (deltaX || deltaY)) {
    return calculateScrollDistribution(deltaX, deltaY, element.parentNode, container, accumulator.concat([scrollInformation]));
  }

  return accumulator.concat([scrollInformation]);
}
function calculateScrollDistribution(deltaX, deltaY, element, container, accumulator = []) {
  const scrollInformation = {
    element,
    scrollLeft: 0,
    scrollTop: 0
  };
  const scrollLeftMax = element.scrollWidth - element.clientWidth;
  const scrollTopMax = element.scrollHeight - element.clientHeight;

  const availableScroll = {
    deltaXNegative: -element.scrollLeft,
    deltaXPositive: scrollLeftMax - element.scrollLeft,
    deltaYNegative: -element.scrollTop,
    deltaYPositive: scrollTopMax - element.scrollTop
  };

  const elementStyle = window.getComputedStyle(element);

  if (elementStyle.overflowX !== 'hidden') {
    // The `deltaX` can be larger than the available scroll for the element, thus overshooting.
    // The result of that is that it scrolls the element as far as possible. We don't need to
    // calculate exactly because we reduce the amount of desired scroll for the
    // parent elements by the correct amount below.
    scrollInformation.scrollLeft = element.scrollLeft + deltaX;
    if (deltaX > availableScroll.deltaXPositive) {
      deltaX = deltaX - availableScroll.deltaXPositive;
    } else if (deltaX < availableScroll.deltaXNegative) {
      deltaX = deltaX - availableScroll.deltaXNegative;
    } else {
      deltaX = 0;
    }
  }

  if (elementStyle.overflowY !== 'hidden') {
    scrollInformation.scrollTop = element.scrollTop + deltaY;
    if (deltaY > availableScroll.deltaYPositive) {
      deltaY = deltaY - availableScroll.deltaYPositive;
    } else if (deltaY < availableScroll.deltaYNegative) {
      deltaY = deltaY - availableScroll.deltaYNegative;
    } else {
      deltaY = 0;
    }
  }

  if (element !== container && (deltaX || deltaY)) {
    return calculateScrollDistribution(deltaX, deltaY, element.parentNode, container, accumulator.concat([scrollInformation]));
  }

  return accumulator.concat([scrollInformation]);
}
function calculateScrollDistribution ( deltaX , deltaY , element , container , accumulator = [ ] ) { const scrollInformation = { element , scrollLeft : 0 , scrollTop : 0 } ; const scrollLeftMax = element . scrollWidth - element . clientWidth ; const scrollTopMax = element . scrollHeight - element . clientHeight ; const availableScroll = { deltaXNegative : - element . scrollLeft , deltaXPositive : scrollLeftMax - element . scrollLeft , deltaYNegative : - element . scrollTop , deltaYPositive : scrollTopMax - element . scrollTop } ; const elementStyle = window . getComputedStyle ( element ) ; if ( elementStyle . overflowX !== 'hidden' ) { // The `deltaX` can be larger than the available scroll for the element, thus overshooting. // The result of that is that it scrolls the element as far as possible. We don't need to // calculate exactly because we reduce the amount of desired scroll for the // parent elements by the correct amount below. scrollInformation . scrollLeft = element . scrollLeft + deltaX ; if ( deltaX > availableScroll . deltaXPositive ) { deltaX = deltaX - availableScroll . deltaXPositive ; } else if ( deltaX < availableScroll . deltaXNegative ) { deltaX = deltaX - availableScroll . deltaXNegative ; } else { deltaX = 0 ; } } if ( elementStyle . overflowY !== 'hidden' ) { scrollInformation . scrollTop = element . scrollTop + deltaY ; if ( deltaY > availableScroll . deltaYPositive ) { deltaY = deltaY - availableScroll . deltaYPositive ; } else if ( deltaY < availableScroll . deltaYNegative ) { deltaY = deltaY - availableScroll . deltaYNegative ; } else { deltaY = 0 ; } } if ( element !== container && ( deltaX || deltaY ) ) { return calculateScrollDistribution ( deltaX , deltaY , element . parentNode , container , accumulator . concat ( [ scrollInformation ] ) ) ; } return accumulator . concat ( [ scrollInformation ] ) ; }
Calculates the scroll distribution for `element` inside` container.

@param {Number} deltaX
@param {Number} deltaY
@param {Element} element
@param {Element} container
@param {ScrollInformation[]} accumulator
@return {ScrollInforamtion}
Calculates the scroll distribution for element inside container .