'use strict';

var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
require('core-js/modules/es.array.filter.js');
require('core-js/modules/es.array.from.js');
require('core-js/modules/es.array.map.js');
require('core-js/modules/es.object.to-string.js');
require('core-js/modules/es.string.iterator.js');
var React = require('react');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var _slicedToArray__default = /*#__PURE__*/_interopDefault(_slicedToArray);

var RESIZE_DEBOUNCE_MS = 150;
var POST_RESIZE_SETTLE_MS = 80;
var INITIAL_SETTLE_MS = 80;

/**
 * Resolve the layout node that represents the full horizontal space available
 * for inline actions. Prefer an explicit ref, but fall back to nearby parents
 * so the hook still works when the caller does not provide one.
 */
var getLayoutNode = function getLayoutNode(layoutRef, container) {
  return (layoutRef === null || layoutRef === void 0 ? void 0 : layoutRef.current) || (container === null || container === void 0 ? void 0 : container.parentElement) || (container === null || container === void 0 ? void 0 : container.offsetParent) || null;
};

/**
 * Normalize excluded-width input so the rest of the hook can always work with
 * an array of selectors.
 */
var getExcludedSelectors = function getExcludedSelectors(excludedWidthSelector) {
  return Array.isArray(excludedWidthSelector) ? excludedWidthSelector : [excludedWidthSelector].filter(Boolean);
};

/**
 * Sum the widths of sibling regions that permanently consume horizontal space,
 * such as selection summary text or a cancel button.
 */
var getExcludedWidth = function getExcludedWidth(layoutNode, selectors) {
  return !layoutNode || !selectors.length ? 0 : selectors.reduce(function (totalWidth, selector) {
    var element = layoutNode.querySelector(selector);
    return totalWidth + ((element === null || element === void 0 ? void 0 : element.offsetWidth) || 0);
  }, 0);
};

/**
 * Compute the width that is actually available for inline actions after fixed
 * sibling regions have been removed.
 */
var getAvailableWidth = function getAvailableWidth(layoutNode, excludedWidth) {
  return layoutNode !== null && layoutNode !== void 0 && layoutNode.clientWidth ? Math.max(layoutNode.clientWidth - excludedWidth, 0) : 0;
};

/**
 * Measure all candidate inline action widths from the current DOM. The caller
 * is responsible for keeping hidden items measurable in the DOM.
 */
var getItemWidths = function getItemWidths(container, itemSelector) {
  return Array.from(container.querySelectorAll(itemSelector)).map(function (element, index) {
    return {
      index: index,
      width: element.offsetWidth
    };
  });
};

/**
 * Calculate how many inline actions can fit when some width may need to be
 * reserved for the overflow trigger itself.
 */
var calculateFittingInlineCount = function calculateFittingInlineCount(_ref) {
  var itemWidths = _ref.itemWidths,
    containerWidth = _ref.containerWidth,
    staticOverflowCount = _ref.staticOverflowCount,
    fallbackOverflowWidth = _ref.fallbackOverflowWidth;
  var totalItemsWidth = itemWidths.reduce(function (total, item) {
    return total + item.width;
  }, 0);

  // Reserve overflow trigger width in either of these cases:
  // - some actions are always forced into overflow
  // - all visible candidates together do not fit inline
  var shouldReserveOverflowSpace = staticOverflowCount > 0 || totalItemsWidth + fallbackOverflowWidth > containerWidth;
  var overflowWidth = shouldReserveOverflowSpace ? fallbackOverflowWidth : 0;
  var nextInlineCount = 0;
  var usedWidth = 0;
  for (var index = 0; index < itemWidths.length; index += 1) {
    var remainingItems = itemWidths.length - (index + 1);
    var shouldReserveOverflowWidth = staticOverflowCount > 0 || remainingItems > 0 || shouldReserveOverflowSpace;
    var reservedWidth = shouldReserveOverflowWidth ? overflowWidth : 0;
    if (usedWidth + itemWidths[index].width + reservedWidth > containerWidth) {
      break;
    }
    usedWidth += itemWidths[index].width;
    nextInlineCount = index + 1;
  }
  return nextInlineCount;
};

/**
 * Calculate how many inline actions can remain visible before the remaining
 * actions must move into overflow.
 *
 * Measurement strategy:
 * - Use an explicit layout container when available.
 * - Subtract any sibling regions that permanently occupy width
 *   (for example selected-count summary / cancel button).
 * - Measure the natural width of all candidate inline actions.
 * - Reserve overflow trigger width when static overflow exists or when not all
 *   actions can fit inline.
 *
 * Important implementation detail:
 * Items are measured from already-rendered DOM nodes. Hidden inline actions
 * should remain measurable in the DOM; otherwise width calculation will
 * fluctuate between renders.
 *
 * @param {Object} params Hook parameters
 * @param {boolean} params.enabled Whether measurement logic should run
 * @param {Array} params.items Source items represented by rendered DOM nodes
 * @param {React.RefObject<HTMLElement>} params.containerRef Ref to the inline items container
 * @param {React.RefObject<HTMLElement>} params.overflowTriggerRef Ref to the visible overflow trigger container
 * @param {string} params.itemSelector Selector used to find rendered inline item nodes inside the container
 * @param {number} params.staticOverflowCount Count of items that are always rendered in overflow
 * @param {React.RefObject<HTMLElement>} [params.layoutRef] Optional ref to the outer layout container
 * @param {string|string[]} [params.excludedWidthSelector] Selector or selector list for sibling regions whose widths should be excluded from available inline space
 * @param {number} [params.fallbackOverflowWidth=48] Width reserved for the overflow trigger when it is needed
 * @returns {number|null} Number of items that should remain inline, or null when disabled
 */
var useResponsiveInlineCount = function useResponsiveInlineCount(_ref2) {
  var enabled = _ref2.enabled,
    items = _ref2.items,
    containerRef = _ref2.containerRef,
    overflowTriggerRef = _ref2.overflowTriggerRef,
    itemSelector = _ref2.itemSelector,
    _ref2$staticOverflowC = _ref2.staticOverflowCount,
    staticOverflowCount = _ref2$staticOverflowC === void 0 ? 0 : _ref2$staticOverflowC,
    _ref2$layoutRef = _ref2.layoutRef,
    layoutRef = _ref2$layoutRef === void 0 ? undefined : _ref2$layoutRef,
    _ref2$excludedWidthSe = _ref2.excludedWidthSelector,
    excludedWidthSelector = _ref2$excludedWidthSe === void 0 ? '' : _ref2$excludedWidthSe,
    _ref2$fallbackOverflo = _ref2.fallbackOverflowWidth,
    fallbackOverflowWidth = _ref2$fallbackOverflo === void 0 ? 48 : _ref2$fallbackOverflo;
  var _useState = React.useState(null),
    _useState2 = _slicedToArray__default.default(_useState, 2),
    inlineCount = _useState2[0],
    setInlineCount = _useState2[1];
  React.useEffect(function () {
    if (!enabled) {
      setInlineCount(null);
      return undefined;
    }
    var frameId = null;
    var settleTimeoutId = null;
    var resizeDebounceTimeoutId = null;
    var postResizeSettleTimeoutId = null;
    var resizeObserver = null;
    var initialContainer = containerRef.current;
    var layoutNode = getLayoutNode(layoutRef, initialContainer);
    var cleanupScheduledWork = function cleanupScheduledWork() {
      if (frameId) {
        cancelAnimationFrame(frameId);
      }
      if (settleTimeoutId) {
        window.clearTimeout(settleTimeoutId);
      }
      if (resizeDebounceTimeoutId) {
        window.clearTimeout(resizeDebounceTimeoutId);
      }
      if (postResizeSettleTimeoutId) {
        window.clearTimeout(postResizeSettleTimeoutId);
      }
    };
    var calculateInlineCount = function calculateInlineCount() {
      var container = containerRef.current;
      if (!container || !items.length) {
        setInlineCount(items.length);
        return;
      }
      var itemWidths = getItemWidths(container, itemSelector);
      if (!itemWidths.length) {
        setInlineCount(0);
        return;
      }
      var excludedSelectors = getExcludedSelectors(excludedWidthSelector);
      var excludedWidth = getExcludedWidth(layoutNode, excludedSelectors);

      // Available inline width comes from the outer layout width after removing
      // regions that permanently consume horizontal space.
      var containerWidth = getAvailableWidth(layoutNode, excludedWidth);
      if (!containerWidth) {
        setInlineCount(items.length);
        return;
      }
      var nextInlineCount = calculateFittingInlineCount({
        itemWidths: itemWidths,
        containerWidth: containerWidth,
        staticOverflowCount: staticOverflowCount,
        fallbackOverflowWidth: fallbackOverflowWidth
      });
      setInlineCount(function (previousCount) {
        return previousCount === nextInlineCount ? previousCount : nextInlineCount;
      });
    };
    var scheduleCalculation = function scheduleCalculation() {
      if (frameId) {
        cancelAnimationFrame(frameId);
      }
      frameId = requestAnimationFrame(calculateInlineCount);
    };
    scheduleCalculation();
    settleTimeoutId = window.setTimeout(function () {
      scheduleCalculation();
    }, INITIAL_SETTLE_MS);
    var debounceCalculation = function debounceCalculation() {
      if (resizeDebounceTimeoutId) {
        window.clearTimeout(resizeDebounceTimeoutId);
      }
      if (postResizeSettleTimeoutId) {
        window.clearTimeout(postResizeSettleTimeoutId);
      }
      resizeDebounceTimeoutId = window.setTimeout(function () {
        scheduleCalculation();
        postResizeSettleTimeoutId = window.setTimeout(function () {
          scheduleCalculation();
        }, POST_RESIZE_SETTLE_MS);
      }, RESIZE_DEBOUNCE_MS);
    };
    var handleResize = function handleResize() {
      debounceCalculation();
    };
    if (typeof ResizeObserver !== 'undefined') {
      resizeObserver = new ResizeObserver(function () {
        debounceCalculation();
      });
      if (layoutNode) {
        resizeObserver.observe(layoutNode);
      }
    }
    window.addEventListener('resize', handleResize);
    return function () {
      cleanupScheduledWork();
      if (resizeObserver) {
        resizeObserver.disconnect();
      }
      window.removeEventListener('resize', handleResize);
    };
  }, [containerRef, enabled, excludedWidthSelector, fallbackOverflowWidth, itemSelector, items, layoutRef, overflowTriggerRef, staticOverflowCount]);
  return inlineCount;
};
var useResponsiveInlineCount$1 = useResponsiveInlineCount;

// Made with Bob

module.exports = useResponsiveInlineCount$1;
