"use strict";

var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ToolbarArrowKeyNavigationProvider = exports.KeyDownHandlerContext = void 0;
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@emotion/react");
var _elementBrowser = require("../../element-browser");
var _messages = require("../../messages");
var _mediaInsert = require("../../messages/media-insert");
var _ui = require("../../ui");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
/**
 * @jsxRuntime classic
 * @jsx jsx
 */

// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports -- Ignored via go/DSP-18766; jsx required at runtime for @jsxRuntime classic

/*
 **  The context is used to handle the keydown events of submenus.
 **  Because the keyboard navigation is explicitly managed for main toolbar items
 **  Few key presses such as Tab,Arrow Right/Left need ot be handled here via context
 */
var KeyDownHandlerContext = exports.KeyDownHandlerContext = /*#__PURE__*/_react.default.createContext({
  handleArrowLeft: function handleArrowLeft() {},
  handleArrowRight: function handleArrowRight() {},
  handleTab: function handleTab() {}
});
var centeredToolbarContainer = (0, _react2.css)({
  display: 'flex',
  width: '100%',
  alignItems: 'center'
});

/**
 * This component is a wrapper of main toolbar which listens to keydown events of children
 * and handles left/right arrow key navigation for all focusable elements
 * @param
 * @returns
 */
// eslint-disable-next-line @atlaskit/volt-strict-mode/no-multiple-exports
var ToolbarArrowKeyNavigationProvider = exports.ToolbarArrowKeyNavigationProvider = function ToolbarArrowKeyNavigationProvider(_ref) {
  var children = _ref.children,
    editorView = _ref.editorView,
    childComponentSelector = _ref.childComponentSelector,
    handleEscape = _ref.handleEscape,
    disableArrowKeyNavigation = _ref.disableArrowKeyNavigation,
    isShortcutToFocusToolbar = _ref.isShortcutToFocusToolbar,
    editorAppearance = _ref.editorAppearance,
    useStickyToolbar = _ref.useStickyToolbar,
    intl = _ref.intl;
  var wrapperRef = (0, _react.useRef)(null);
  var selectedItemIndex = (0, _react.useRef)(0);
  var incrementIndex = (0, _react.useCallback)(function (list) {
    var index = 0;
    if (document.activeElement) {
      // Ignored via go/ees005
      // eslint-disable-next-line @atlaskit/editor/no-as-casting
      index = list.indexOf(document.activeElement);
      index = (index + 1) % list.length;
    }
    selectedItemIndex.current = index;
  }, []);
  var decrementIndex = (0, _react.useCallback)(function (list) {
    var index = 0;
    if (document.activeElement) {
      // Ignored via go/ees005
      // eslint-disable-next-line @atlaskit/editor/no-as-casting
      index = list.indexOf(document.activeElement);
      index = (list.length + index - 1) % list.length;
    }
    selectedItemIndex.current = index;
  }, []);
  var handleArrowRightMemoized = (0, _react.useCallback)(function () {
    var _filteredFocusableEle;
    var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
    incrementIndex(filteredFocusableElements);
    (_filteredFocusableEle = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle === void 0 || _filteredFocusableEle.focus();
  }, [incrementIndex]);
  var handleArrowLeftMemoized = (0, _react.useCallback)(function () {
    var _filteredFocusableEle2;
    var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
    decrementIndex(filteredFocusableElements);
    (_filteredFocusableEle2 = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle2 === void 0 || _filteredFocusableEle2.focus();
  }, [decrementIndex]);
  var handleTabMemoized = (0, _react.useCallback)(function () {
    var _filteredFocusableEle3;
    var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
    (_filteredFocusableEle3 = filteredFocusableElements[selectedItemIndex.current]) === null || _filteredFocusableEle3 === void 0 || _filteredFocusableEle3.focus();
  }, []);
  var handleTabLocal = function handleTabLocal() {
    var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
    filteredFocusableElements.forEach(function (element) {
      element.setAttribute('tabindex', '-1');
    });
    filteredFocusableElements[selectedItemIndex.current].setAttribute('tabindex', '0');
  };
  var focusAndScrollToElement = function focusAndScrollToElement(element) {
    var scrollToElement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
    if (scrollToElement) {
      element === null || element === void 0 || element.scrollIntoView({
        behavior: 'smooth',
        block: 'center',
        inline: 'nearest'
      });
    }
    element.focus();
  };
  var submenuKeydownHandleContext = (0, _react.useMemo)(function () {
    return {
      handleArrowLeft: handleArrowLeftMemoized,
      handleArrowRight: handleArrowRightMemoized,
      handleTab: handleTabMemoized
    };
  }, [handleArrowLeftMemoized, handleArrowRightMemoized, handleTabMemoized]);
  (0, _react.useLayoutEffect)(function () {
    if (!wrapperRef.current || disableArrowKeyNavigation) {
      return;
    }
    var element = wrapperRef.current;

    /**
     * To handle the key events on the list
     * @param event
     */
    var handleKeyDown = function handleKeyDown(event) {
      var _document$querySelect, _document$querySelect2, _wrapperRef$current, _wrapperRef$current2;
      // To trap the focus inside the horizontal toolbar for left and right arrow keys
      var targetElement = event.target;
      if (targetElement instanceof HTMLElement && !targetElement.closest("".concat(childComponentSelector))) {
        return;
      }
      if (targetElement instanceof HTMLElement && (_document$querySelect = document.querySelector('[data-role="droplistContent"], [data-test-id="color-picker-menu"], [data-emoji-picker-container="true"]')) !== null && _document$querySelect !== void 0 && _document$querySelect.contains(targetElement) || targetElement instanceof HTMLElement && (_document$querySelect2 = document.querySelector('[data-test-id="color-picker-menu"]')) !== null && _document$querySelect2 !== void 0 && _document$querySelect2.contains(targetElement) || event.key === 'ArrowUp' || event.key === 'ArrowDown' || disableArrowKeyNavigation) {
        return;
      }
      var menuWrapper = document.querySelector('.menu-key-handler-wrapper');
      if (menuWrapper) {
        // if menu wrapper exists, then a menu is open and arrow keys will be handled by MenuArrowKeyNavigationProvider
        return;
      }
      var elementBrowser = wrapperRef === null || wrapperRef === void 0 || (_wrapperRef$current = wrapperRef.current) === null || _wrapperRef$current === void 0 ? void 0 : _wrapperRef$current.querySelector("#".concat(_elementBrowser.ELEMENT_BROWSER_ID));
      if (elementBrowser) {
        // if element browser is open, then arrow keys will be handled by MenuArrowKeyNavigationProvider
        return;
      }
      var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
      if (!filteredFocusableElements || (filteredFocusableElements === null || filteredFocusableElements === void 0 ? void 0 : filteredFocusableElements.length) === 0) {
        return;
      }

      // If the target element is the media picker then navigation is handled by the media picker
      if (targetElement instanceof HTMLElement && targetElement.closest("[aria-label=\"".concat(intl.formatMessage(_mediaInsert.mediaInsertMessages.mediaPickerPopupAriaLabel), "\"]"))) {
        return;
      }
      if (targetElement instanceof HTMLElement && !((_wrapperRef$current2 = wrapperRef.current) !== null && _wrapperRef$current2 !== void 0 && _wrapperRef$current2.contains(targetElement))) {
        selectedItemIndex.current = -1;
      } else {
        selectedItemIndex.current = targetElement instanceof HTMLElement && filteredFocusableElements.indexOf(targetElement) > -1 ? filteredFocusableElements.indexOf(targetElement) : selectedItemIndex.current;
      }

      // do not scroll to focused element for sticky toolbar when navigating with arrows to avoid unnesessary scroll jump
      var allowScrollToElement = !(editorAppearance === 'comment' && !!useStickyToolbar);
      switch (event.key) {
        case 'ArrowRight':
          incrementIndex(filteredFocusableElements);
          focusAndScrollToElement(filteredFocusableElements[selectedItemIndex.current], allowScrollToElement);
          event.preventDefault();
          break;
        case 'ArrowLeft':
          decrementIndex(filteredFocusableElements);
          focusAndScrollToElement(filteredFocusableElements[selectedItemIndex.current], allowScrollToElement);
          event.preventDefault();
          break;
        case 'Tab':
          handleTabLocal();
          break;
        case 'Escape':
          // Ignored via go/ees005
          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
          handleEscape(event);
          break;
        default:
      }
    };
    var globalKeyDownHandler = function globalKeyDownHandler(event) {
      // To focus the first element in the toolbar
      // Ignored via go/ees005
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      if (isShortcutToFocusToolbar(event)) {
        var _filteredFocusableEle4, _filteredFocusableEle5, _filteredFocusableEle6;
        var filteredFocusableElements = getFilteredFocusableElements(wrapperRef === null || wrapperRef === void 0 ? void 0 : wrapperRef.current);
        (_filteredFocusableEle4 = filteredFocusableElements[0]) === null || _filteredFocusableEle4 === void 0 || _filteredFocusableEle4.focus();

        // Button component from DS removes focus ring when :focus:not(:focus-visible) is true
        // Since here we programmatically focus the first button in the toolbar (as suppose to keyboard navigation), browser does not always force focus-visible to true
        // which is why the first button in the toolbar is not shown with focus ring
        // The workaround is add a new classname so we add back focus ring when the button is focused
        if (((_filteredFocusableEle5 = filteredFocusableElements[0]) === null || _filteredFocusableEle5 === void 0 ? void 0 : _filteredFocusableEle5.tagName) === 'BUTTON') {
          filteredFocusableElements[0].classList.add('first-floating-toolbar-button');
        }
        (_filteredFocusableEle6 = filteredFocusableElements[0]) === null || _filteredFocusableEle6 === void 0 || _filteredFocusableEle6.scrollIntoView({
          behavior: 'smooth',
          block: 'center',
          inline: 'nearest'
        });
      }
    };

    // Ignored via go/ees005
    // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
    element === null || element === void 0 || element.addEventListener('keydown', handleKeyDown);
    var editorViewDom = editorView === null || editorView === void 0 ? void 0 : editorView.dom;
    if (isShortcutToFocusToolbar) {
      // Ignored via go/ees005
      // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
      editorViewDom === null || editorViewDom === void 0 || editorViewDom.addEventListener('keydown', globalKeyDownHandler);
    }
    return function () {
      // Ignored via go/ees005
      // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
      element === null || element === void 0 || element.removeEventListener('keydown', handleKeyDown);
      if (isShortcutToFocusToolbar) {
        // Ignored via go/ees005
        // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
        editorViewDom === null || editorViewDom === void 0 || editorViewDom.removeEventListener('keydown', globalKeyDownHandler);
      }
    };
  }, [selectedItemIndex, wrapperRef, editorView, disableArrowKeyNavigation, handleEscape, childComponentSelector, incrementIndex, decrementIndex, isShortcutToFocusToolbar, editorAppearance, useStickyToolbar, intl]);
  return (0, _react2.jsx)("div", {
    css: editorAppearance === 'comment' && centeredToolbarContainer
    // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
    ,
    className: "custom-key-handler-wrapper",
    ref: wrapperRef,
    role: "toolbar",
    "aria-label": intl.formatMessage(_messages.fullPageMessages.toolbarLabel),
    "aria-controls": _ui.EDIT_AREA_ID
  }, (0, _react2.jsx)(KeyDownHandlerContext.Provider, {
    value: submenuKeydownHandleContext
  }, children));
};
function getFocusableElements(rootNode) {
  if (!rootNode) {
    return [];
  }
  var focusableModalElements = rootNode.querySelectorAll('a[href], button:not([disabled]), textarea, input, select, div[tabindex="-1"], div[tabindex="0"]') || [];
  return Array.from(focusableModalElements);
}
function isElementOrAncestorHiddenOrDisabled(element, rootNode) {
  var currentElement = element;
  while (currentElement && currentElement !== rootNode && currentElement !== document.body) {
    var style = window.getComputedStyle(currentElement);

    // Check if current element is hidden
    if (style.visibility === 'hidden' || style.display === 'none') {
      return true;
    }

    // Check if current element is disabled
    if (currentElement.hasAttribute('disabled') || currentElement.getAttribute('aria-disabled') === 'true' || currentElement.disabled === true) {
      return true;
    }

    // Move to parent element
    currentElement = currentElement.parentElement;
  }
  return false;
}
function getFilteredFocusableElements(rootNode) {
  // The focusable elements from child components such as dropdown menus / popups are ignored
  return getFocusableElements(rootNode).filter(function (elm) {
    // Check if element or any ancestor is hidden or disabled
    var isHiddenOrDisabled = isElementOrAncestorHiddenOrDisabled(elm, rootNode);
    return !elm.closest('[data-role="droplistContent"]') && !elm.closest('[data-emoji-picker-container="true"]') && !elm.closest('[data-test-id="color-picker-menu"]') && !elm.closest('.scroll-buttons') && !isHiddenOrDisabled;
  });
}