"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = useOptionKeyboardNavigation;
var _react = require("react");
const scrollIntoOption = (containerEl, optionEl, scrollOffset) => {
  const containerRect = containerEl.getBoundingClientRect();
  const optionRect = optionEl.getBoundingClientRect();
  if (optionRect.bottom > containerRect.bottom) {
    containerEl.scrollTop = Math.min(optionEl.offsetTop + optionEl.clientHeight - containerEl.offsetHeight - scrollOffset, containerEl.scrollHeight);
  } else if (optionRect.top < containerRect.top) {
    containerEl.scrollTop = Math.max(optionEl.offsetTop - scrollOffset, 0);
  }
};

/**
 * Navigates through and selects options in lists/dropdowns via keyboard
 * @param {array} options - The options that could be selected
 * @param {string} optionId - Property key of the unique identifier for each item
 * @param {function} select - Function handler invoked when an item is selected by pressing Enter
 * @param {function} close  - Function handler invoked when selection is cancelled by Esc or Tab.
 * @param {array} optionsRefs - optional param for handling scroll with arrow keys
 * @param {ref} scrollableContainerRef - optional param for handling scroll with arrow keys
 * @param {number} scrollOffset - optional param for handling scroll with arrow keys
 */
function useOptionKeyboardNavigation(options, optionId, select, close, optionsRefs, scrollableContainerRef, scrollOffset = 0, disabilityPropName, inputRef) {
  const [activeOption, makeActive] = (0, _react.useState)(options.length ? options[0][optionId] : -1);
  // used to outline element when using keyboard
  const [focusedOption, makeFocused] = (0, _react.useState)(-1);
  const handleContainerScroll = active => {
    const scrollableContainerRefAvailable = scrollableContainerRef && scrollableContainerRef.current;
    if (!active || !optionsRefs || !scrollableContainerRefAvailable) {
      return;
    }
    const currentOptionRef = optionsRefs[String(active)];
    if (currentOptionRef && currentOptionRef.current) {
      scrollIntoOption(scrollableContainerRef.current, currentOptionRef.current, scrollOffset);
    }
  };
  const isEnabled = (0, _react.useCallback)(opt => !disabilityPropName || !opt[disabilityPropName], [disabilityPropName]);
  (0, _react.useEffect)(() => {
    const handleKeyDown = event => {
      const keyboardEvent = event;
      const {
        key
      } = keyboardEvent;
      if (['Escape', 'Tab'].indexOf(key) !== -1) {
        event.preventDefault();
        makeFocused(-1);
        return close();
      }
      if (['ArrowDown', 'ArrowUp', 'Enter'].indexOf(key) !== -1) {
        event.preventDefault();
        const activeIndex = options.findIndex(option => option[optionId] === activeOption);
        if (!options.length) {
          return;
        }
        if (key === 'Enter') {
          const option = activeIndex !== -1 ? options[activeIndex] : options[0];
          if (isEnabled(option)) {
            select(option);
            makeFocused(-1);
            return close();
          }
        }
        if (key === 'ArrowDown') {
          if (activeIndex !== options.length - 1) {
            const nextActiveIndex = activeIndex === -1 ? 0 : activeIndex + 1;
            const nextActiveOptionId = options.slice(nextActiveIndex).find(opt => isEnabled(opt))?.[optionId];
            if (nextActiveOptionId === undefined) {
              return;
            }
            handleContainerScroll(nextActiveOptionId);
            makeFocused(nextActiveOptionId);
            return makeActive(nextActiveOptionId);
          }
          makeFocused(options?.[options.length - 1][optionId]);
        }
        if (key === 'ArrowUp') {
          if (activeIndex !== 0) {
            const nextActiveIndex = activeIndex === -1 ? 0 : activeIndex;
            const nextActiveOptionId = options.slice(0, nextActiveIndex).reverse().find(opt => isEnabled(opt))?.[optionId];
            if (nextActiveOptionId === undefined) {
              return;
            }
            handleContainerScroll(nextActiveOptionId);
            makeFocused(nextActiveOptionId);
            return makeActive(nextActiveOptionId);
          }
          makeFocused(options?.[0][optionId]);
        }
      }
    };
    const element = inputRef?.current ?? document;
    element.addEventListener('keydown', handleKeyDown);
    return () => {
      element.removeEventListener('keydown', handleKeyDown);
    };
  }, [activeOption, options, optionId, inputRef]);
  const makeUnactive = () => makeActive(-1);
  return [activeOption, makeActive, makeUnactive, focusedOption];
}