"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.Tabs = void 0;
var _compat = require("preact/compat");
var _Tab = _interopRequireDefault(require("./Tab"));
var _TabPanel = _interopRequireDefault(require("./TabPanel"));
var _classnames = _interopRequireDefault(require("classnames"));
var _get = _interopRequireDefault(require("lodash/get"));
var _jsxRuntime = require("preact/compat/jsx-runtime");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/** CONSTANTS
 * Adding in the constant values for keycodes
 * to handle onKeyDown events
 */
const LEFT_ARROW = 'ArrowLeft';
const RIGHT_ARROW = 'ArrowRight';

/**
 * Determine if a React component is a TabPanel
 * @param {React.Node} child - a React component
 * @return {Boolean} Is this a TabPanel component?
 */
const isTabPanel = child => {
  const componentName = (0, _get.default)(child, 'type.displayName') || (0, _get.default)(child, 'type.name');

  // Check child.type first and as a fallback, check child.type.displayName follow by child.type.name
  return child && (child.type === _TabPanel.default || componentName === 'TabPanel');
};

/**
 * Get the id of the first TabPanel child
 * @param {Object} props
 * @return {String} The id
 */
const getDefaultSelectedId = props => {
  let selectedId;

  // TODO: Use the panelChildren method to pass in an array
  // of panels, instead of doing it here...
  _compat.Children.forEach(props.children, function (child) {
    if (isTabPanel(child) && !selectedId) {
      selectedId = child.props.id;
    }
  });
  return selectedId;
};

/**
 * Generate an id for a panel's associated tab if one doesn't yet exist
 * @param {Object} TabPanel component
 * @return {String} Tab ID
 */
const panelTabId = panel => {
  return panel.props.tabId ?? `${panel.props.id}__tab`;
};

/**
 * `Tabs` is a container component that manages the state of your tabs for you.
 * In most cases, you'll want to use this component rather than the
 * presentational components (`Tab`, `TabPanel`) on their own.
 *
 * A `TabPanel` is a presentational component which accepts a tab's content as
 * its `children`.
 *
 * For information about how and when to use this component,
 * [refer to its full documentation page](https://design.cms.gov/components/tabs/).
 */
const Tabs = props => {
  const initialSelectedId = props.defaultSelectedId || getDefaultSelectedId(props);
  const [internalSelectedId, setSelectedId] = (0, _compat.useState)(initialSelectedId);
  const isControlled = props.selectedId !== undefined;
  const selectedId = isControlled ? props.selectedId : internalSelectedId;
  const listClasses = (0, _classnames.default)('ds-c-tabs', props.tablistClassName);
  // using useRef hook to keep track of elements to focus
  const tabsRef = (0, _compat.useRef)({});

  /**
   * Update the URL in the browser without adding a new entry to the history.
   * @param {String} url - Absolute or relative URL
   */
  const replaceState = url => {
    if (window.history) {
      window.history.replaceState({}, document.title, url);
    }
  };
  const panelChildren = () => {
    return _compat.Children.toArray(props.children).filter(isTabPanel);
  };
  const handleSelectedTabChange = newSelectedId => {
    const {
      onChange
    } = props;
    if (onChange) {
      onChange(newSelectedId, selectedId);
    }
    tabsRef.current[newSelectedId].focus();
    replaceState(tabsRef.current[newSelectedId].href);
    setSelectedId(newSelectedId);
  };
  const handleTabClick = (evt, panelId) => {
    evt.preventDefault();
    handleSelectedTabChange(panelId);
  };
  const handleTabKeyDown = (evt, panelId) => {
    const tabs = panelChildren();
    const tabIndex = tabs.findIndex(elem => elem.props.id === panelId);
    let target;
    switch (evt.key) {
      case LEFT_ARROW:
        evt.preventDefault();
        if (tabIndex === 0) {
          const prevTab = tabs[tabs.length - 1];
          target = prevTab.props.id;
        } else {
          const prevTab = tabs[tabIndex - 1];
          target = prevTab.props.id;
        }
        handleSelectedTabChange(target);
        break;
      case RIGHT_ARROW:
        evt.preventDefault();
        if (tabIndex === tabs.length - 1) {
          const currentTab = tabs[0];
          target = currentTab.props.id;
        } else {
          const nextTab = tabs[tabIndex + 1];
          target = nextTab.props.id;
        }
        handleSelectedTabChange(target);
        break;
      default:
        break;
    }
  };
  const renderChildren = () => {
    return _compat.Children.map(props.children, child => {
      if (isTabPanel(child) && (0, _compat.isValidElement)(child)) {
        // Extend props on panels before rendering. Also removes any props
        // that don't need passed into TabPanel but are used to generate
        // the Tab components
        return (0, _compat.cloneElement)(child, {
          selected: selectedId === child.props.id,
          tab: undefined,
          tabHref: undefined,
          tabId: panelTabId(child)
        });
      }
      return child;
    });
  };
  const renderTabs = () => {
    const panels = panelChildren();
    const tabs = panels.map(panel => {
      return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tab.default, {
        className: panel.props.tabClassName,
        href: panel.props.tabHref,
        disabled: panel.props.disabled,
        id: panelTabId(panel),
        onClick: handleTabClick,
        onKeyDown: handleTabKeyDown,
        panelId: panel.props.id,
        ref: tab => {
          tabsRef.current[panel.props.id] = tab;
        },
        selected: selectedId === panel.props.id,
        children: panel.props.tab
      }, panel.key);
    });
    return tabs;
  };
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: listClasses,
      role: "tablist",
      children: renderTabs()
    }), renderChildren()]
  });
};
exports.Tabs = Tabs;
var _default = Tabs;
exports.default = _default;