import React__default, { useMemo, useRef, useState, useEffect, useContext, Children, memo } from 'react';
import _pt from 'prop-types';
import { isNumber, forwardRefWithAs, useControlledSwitchWarning, makeId, useControlledState, noop, checkStyles, isFunction, useForkedRef, getElementComputedStyle, useEventCallback, wrapEvent, useIsomorphicLayoutEffect, boolOrBoolString, cloneValidElement, useUpdateEffect, createNamedContext } from '../../utils/dist/utils.esm.esm.js';
import { useDescendantsInit, DescendantProvider, useDescendants, useDescendantKeyDown, useDescendant, createDescendantContext } from '../../descendants/dist/descendants.esm.esm.js';
import { useId } from '../../auto-id/dist/auto-id.esm.esm.js';

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null) return {};
  var target = {};
  var sourceKeys = Object.keys(source);
  var key, i;

  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i];
    if (excluded.indexOf(key) >= 0) continue;
    target[key] = source[key];
  }

  return target;
}

var TabsDescendantsContext = /*#__PURE__*/createDescendantContext("TabsDescendantsContext");
var TabPanelDescendantsContext = /*#__PURE__*/createDescendantContext("TabPanelDescendantsContext");
var TabsContext = /*#__PURE__*/createNamedContext("TabsContext", {});
var TabsKeyboardActivation;

(function (TabsKeyboardActivation) {
  TabsKeyboardActivation["Auto"] = "auto";
  TabsKeyboardActivation["Manual"] = "manual";
})(TabsKeyboardActivation || (TabsKeyboardActivation = {}));

var TabsOrientation;

(function (TabsOrientation) {
  TabsOrientation["Horizontal"] = "horizontal";
  TabsOrientation["Vertical"] = "vertical";
})(TabsOrientation || (TabsOrientation = {})); ////////////////////////////////////////////////////////////////////////////////

/**
 * Tabs
 *
 * The parent component of the tab interface.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#tabs
 */


var Tabs = /*#__PURE__*/forwardRefWithAs(function Tabs(_ref, ref) {
  var _props$id;

  var _ref$as = _ref.as,
      Comp = _ref$as === void 0 ? "div" : _ref$as,
      children = _ref.children,
      defaultIndex = _ref.defaultIndex,
      _ref$orientation = _ref.orientation,
      orientation = _ref$orientation === void 0 ? TabsOrientation.Horizontal : _ref$orientation,
      _ref$index = _ref.index,
      controlledIndex = _ref$index === void 0 ? undefined : _ref$index,
      _ref$keyboardActivati = _ref.keyboardActivation,
      keyboardActivation = _ref$keyboardActivati === void 0 ? TabsKeyboardActivation.Auto : _ref$keyboardActivati,
      onChange = _ref.onChange,
      _ref$readOnly = _ref.readOnly,
      readOnly = _ref$readOnly === void 0 ? false : _ref$readOnly,
      props = _objectWithoutPropertiesLoose(_ref, ["as", "children", "defaultIndex", "orientation", "index", "keyboardActivation", "onChange", "readOnly"]);

  var isControlled = useRef(controlledIndex != null);
  useControlledSwitchWarning(controlledIndex, "index", "Tabs");

  var _id = useId(props.id);

  var id = (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : makeId("tabs", _id); // We only manage focus if the user caused the update vs. a new controlled
  // index coming in.

  var userInteractedRef = useRef(false);
  var selectedPanelRef = useRef(null);
  var isRTL = useRef(false);

  var _useControlledState = useControlledState(controlledIndex, defaultIndex !== null && defaultIndex !== void 0 ? defaultIndex : 0),
      selectedIndex = _useControlledState[0],
      setSelectedIndex = _useControlledState[1];

  var _useState = useState(-1),
      focusedIndex = _useState[0],
      setFocusedIndex = _useState[1];

  var _useDescendantsInit = useDescendantsInit(),
      tabs = _useDescendantsInit[0],
      setTabs = _useDescendantsInit[1];

  var context = useMemo(function () {
    return {
      focusedIndex: focusedIndex,
      id: id,
      isControlled: isControlled.current,
      isRTL: isRTL,
      keyboardActivation: keyboardActivation,
      onFocusPanel: function onFocusPanel() {
        var _selectedPanelRef$cur;

        (_selectedPanelRef$cur = selectedPanelRef.current) === null || _selectedPanelRef$cur === void 0 ? void 0 : _selectedPanelRef$cur.focus();
      },
      onSelectTab: readOnly ? noop : function (index) {
        userInteractedRef.current = true;
        onChange && onChange(index);
        setSelectedIndex(index);
      },
      onSelectTabWithKeyboard: readOnly ? noop : function (index) {
        var _tabs$index$element;

        userInteractedRef.current = true;

        switch (keyboardActivation) {
          case TabsKeyboardActivation.Manual:
            (_tabs$index$element = tabs[index].element) === null || _tabs$index$element === void 0 ? void 0 : _tabs$index$element.focus();
            return;

          case TabsKeyboardActivation.Auto:
          default:
            onChange && onChange(index);
            setSelectedIndex(index);
            return;
        }
      },
      orientation: orientation,
      selectedIndex: selectedIndex,
      selectedPanelRef: selectedPanelRef,
      setFocusedIndex: setFocusedIndex,
      setSelectedIndex: setSelectedIndex,
      userInteractedRef: userInteractedRef
    };
  }, [focusedIndex, id, keyboardActivation, onChange, orientation, readOnly, selectedIndex, setSelectedIndex, tabs]);
  useEffect(function () {
    return checkStyles("tabs");
  }, []);
  return React__default.createElement(DescendantProvider, {
    context: TabsDescendantsContext,
    items: tabs,
    set: setTabs
  }, React__default.createElement(TabsContext.Provider, {
    value: context
  }, React__default.createElement(Comp, Object.assign({}, props, {
    ref: ref,
    "data-reach-tabs": "",
    "data-orientation": orientation,
    id: props.id
  }), isFunction(children) ? children({
    focusedIndex: focusedIndex,
    id: id,
    selectedIndex: selectedIndex
  }) : children)));
});

if (process.env.NODE_ENV !== "production") {
  Tabs.displayName = "Tabs";
  Tabs.propTypes = {
    children: _pt.node.isRequired,
    onChange: _pt.func,
    orientation: /*#__PURE__*/_pt.oneOf( /*#__PURE__*/Object.values(TabsOrientation)),
    index: function index(props, name, compName, location, propName) {
      var val = props[name];

      if (props.index > -1 && props.onChange == null && props.readOnly !== true) {
        return new Error("You provided a value prop to `" + compName + "` without an `onChange` handler. This will render a read-only tabs element. If the tabs should be mutable use `defaultIndex`. Otherwise, set `onChange`.");
      } else if (props[name] != null && !isNumber(props[name])) {
        return new Error("Invalid prop `" + propName + "` supplied to `" + compName + "`. Expected `number`, received `" + (Array.isArray(val) ? "array" : typeof val) + "`.");
      }

      return null;
    },
    defaultIndex: _pt.number
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * TabList
 *
 * The parent component of the tabs.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#tablist
 */


var TabListImpl = /*#__PURE__*/forwardRefWithAs(function TabList(_ref2, forwardedRef) {
  var children = _ref2.children,
      _ref2$as = _ref2.as,
      Comp = _ref2$as === void 0 ? "div" : _ref2$as,
      onKeyDown = _ref2.onKeyDown,
      props = _objectWithoutPropertiesLoose(_ref2, ["children", "as", "onKeyDown"]);

  var _useContext = useContext(TabsContext),
      focusedIndex = _useContext.focusedIndex,
      isControlled = _useContext.isControlled,
      isRTL = _useContext.isRTL,
      keyboardActivation = _useContext.keyboardActivation,
      onSelectTabWithKeyboard = _useContext.onSelectTabWithKeyboard,
      orientation = _useContext.orientation,
      selectedIndex = _useContext.selectedIndex,
      setSelectedIndex = _useContext.setSelectedIndex;

  var tabs = useDescendants(TabsDescendantsContext);
  var ownRef = useRef(null);
  var ref = useForkedRef(forwardedRef, ownRef);
  useEffect(function () {
    if (ownRef.current && (ownRef.current.ownerDocument && ownRef.current.ownerDocument.dir === "rtl" || getElementComputedStyle(ownRef.current, "direction") === "rtl")) {
      isRTL.current = true;
    }
  }, [isRTL]);
  var handleKeyDown = useEventCallback(wrapEvent(onKeyDown, useDescendantKeyDown(TabsDescendantsContext, {
    currentIndex: keyboardActivation === TabsKeyboardActivation.Manual ? focusedIndex : selectedIndex,
    orientation: orientation,
    rotate: true,
    callback: onSelectTabWithKeyboard,
    filter: function filter(tab) {
      return !tab.disabled;
    },
    rtl: isRTL.current
  })));
  useIsomorphicLayoutEffect(function () {
    var _tabs$selectedIndex;

    // In the event an uncontrolled component's selected index is disabled,
    // (this should only happen if the first tab is disabled and no default
    // index is set), we need to override the selection to the next selectable
    // index value.
    if (!isControlled && boolOrBoolString((_tabs$selectedIndex = tabs[selectedIndex]) === null || _tabs$selectedIndex === void 0 ? void 0 : _tabs$selectedIndex.disabled)) {
      var next = tabs.find(function (tab) {
        return !tab.disabled;
      });

      if (next) {
        setSelectedIndex(next.index);
      }
    }
  }, [tabs, isControlled, selectedIndex, setSelectedIndex]);
  return React__default.createElement(Comp // The element that serves as the container for the set of tabs has role
  // `tablist`
  // https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel
  , Object.assign({
    // The element that serves as the container for the set of tabs has role
    // `tablist`
    // https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel
    role: "tablist",
    "aria-orientation": orientation
  }, props, {
    "data-reach-tab-list": "",
    ref: ref,
    onKeyDown: handleKeyDown
  }), Children.map(children, function (child, index) {
    // TODO: Remove in 1.0
    return cloneValidElement(child, {
      isSelected: index === selectedIndex
    });
  }));
});
var TabList = /*#__PURE__*/memo(TabListImpl);

if (process.env.NODE_ENV !== "production") {
  TabList.displayName = "TabList";
  TabListImpl.displayName = "TabList";
  TabListImpl.propTypes = {
    as: _pt.any,
    children: _pt.node
  };
}

/**
 * Tab
 *
 * The interactive element that changes the selected panel.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#tab
 */

var Tab = /*#__PURE__*/forwardRefWithAs(function Tab(_ref3, forwardedRef) {
  var children = _ref3.children,
      _ = _ref3.isSelected,
      _ref3$as = _ref3.as,
      Comp = _ref3$as === void 0 ? "button" : _ref3$as,
      indexProp = _ref3.index,
      disabled = _ref3.disabled,
      onBlur = _ref3.onBlur,
      onFocus = _ref3.onFocus,
      props = _objectWithoutPropertiesLoose(_ref3, ["children", "isSelected", "as", "index", "disabled", "onBlur", "onFocus"]);

  var _useContext2 = useContext(TabsContext),
      tabsId = _useContext2.id,
      onSelectTab = _useContext2.onSelectTab,
      orientation = _useContext2.orientation,
      selectedIndex = _useContext2.selectedIndex,
      userInteractedRef = _useContext2.userInteractedRef,
      setFocusedIndex = _useContext2.setFocusedIndex;

  var ownRef = useRef(null);
  var ref = useForkedRef(forwardedRef, ownRef);
  var index = useDescendant({
    element: ownRef.current,
    disabled: !!disabled
  }, TabsDescendantsContext, indexProp);
  var htmlType = Comp === "button" && props.type == null ? "button" : props.type;
  var isSelected = index === selectedIndex;

  function onSelect() {
    onSelectTab(index);
  }

  useUpdateEffect(function () {
    if (isSelected && ownRef.current && userInteractedRef.current) {
      userInteractedRef.current = false;
      ownRef.current.focus();
    }
  }, [isSelected, userInteractedRef]);
  var handleFocus = useEventCallback(wrapEvent(onFocus, function () {
    setFocusedIndex(index);
  }));
  var handleBlur = useEventCallback(wrapEvent(onFocus, function () {
    setFocusedIndex(-1);
  }));
  return React__default.createElement(Comp // Each element with role `tab` has the property `aria-controls` referring
  // to its associated `tabpanel` element.
  // https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel
  , Object.assign({
    "aria-controls": makeId(tabsId, "panel", index),
    "aria-disabled": disabled,
    "aria-selected": isSelected,
    // Each element that serves as a tab has role `tab` and is contained
    // within the element with role `tablist`.
    // https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel
    role: "tab",
    tabIndex: isSelected ? 0 : -1
  }, props, {
    ref: ref,
    "data-reach-tab": "",
    "data-orientation": orientation,
    "data-selected": isSelected ? "" : undefined,
    disabled: disabled,
    id: makeId(tabsId, "tab", index),
    onClick: onSelect,
    onFocus: handleFocus,
    onBlur: handleBlur,
    type: htmlType
  }), children);
});

if (process.env.NODE_ENV !== "production") {
  Tab.displayName = "Tab";
  Tab.propTypes = {
    children: _pt.node,
    disabled: _pt.bool
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * TabPanels
 *
 * The parent component of the panels.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#tabpanels
 */


var TabPanelsImpl = /*#__PURE__*/forwardRefWithAs(function TabPanels(_ref4, forwardedRef) {
  var children = _ref4.children,
      _ref4$as = _ref4.as,
      Comp = _ref4$as === void 0 ? "div" : _ref4$as,
      props = _objectWithoutPropertiesLoose(_ref4, ["children", "as"]);

  var ownRef = useRef();
  var ref = useForkedRef(ownRef, forwardedRef);

  var _useDescendantsInit2 = useDescendantsInit(),
      tabPanels = _useDescendantsInit2[0],
      setTabPanels = _useDescendantsInit2[1];

  return React__default.createElement(DescendantProvider, {
    context: TabPanelDescendantsContext,
    items: tabPanels,
    set: setTabPanels
  }, React__default.createElement(Comp, Object.assign({}, props, {
    ref: ref,
    "data-reach-tab-panels": ""
  }), children));
});
var TabPanels = /*#__PURE__*/memo(TabPanelsImpl);

if (process.env.NODE_ENV !== "production") {
  TabPanels.displayName = "TabPanels";
  TabPanelsImpl.displayName = "TabPanels";
  TabPanelsImpl.propTypes = {
    as: _pt.any,
    children: _pt.node
  };
}

/**
 * TabPanel
 *
 * The panel that displays when it's corresponding tab is active.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#tabpanel
 */

var TabPanel = /*#__PURE__*/forwardRefWithAs(function TabPanel(_ref5, forwardedRef) {
  var children = _ref5.children,
      ariaLabel = _ref5["aria-label"],
      _ref5$as = _ref5.as,
      Comp = _ref5$as === void 0 ? "div" : _ref5$as,
      props = _objectWithoutPropertiesLoose(_ref5, ["children", "aria-label", "as"]);

  var _useContext3 = useContext(TabsContext),
      selectedPanelRef = _useContext3.selectedPanelRef,
      selectedIndex = _useContext3.selectedIndex,
      tabsId = _useContext3.id;

  var ownRef = useRef(null);
  var index = useDescendant({
    element: ownRef.current
  }, TabPanelDescendantsContext);
  var isSelected = index === selectedIndex;
  var id = makeId(tabsId, "panel", index);
  var ref = useForkedRef(forwardedRef, ownRef, isSelected ? selectedPanelRef : null);
  return React__default.createElement(Comp // Each element with role `tabpanel` has the property `aria-labelledby`
  // referring to its associated tab element.
  , Object.assign({
    "aria-labelledby": makeId(tabsId, "tab", index),
    hidden: !isSelected,
    // Each element that contains the content panel for a tab has role
    // `tabpanel`.
    // https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel
    role: "tabpanel",
    tabIndex: isSelected ? 0 : -1
  }, props, {
    ref: ref,
    "data-reach-tab-panel": "",
    id: id
  }), children);
});

if (process.env.NODE_ENV !== "production") {
  TabPanel.displayName = "TabPanel";
  TabPanel.propTypes = {
    as: _pt.any,
    children: _pt.node
  };
} ////////////////////////////////////////////////////////////////////////////////

/**
 * A hook that exposes data for a given `Tabs` component to its descendants.
 *
 * @see Docs https://reacttraining.com/reach-ui/tabs#usetabscontext
 */


function useTabsContext() {
  var _useContext4 = useContext(TabsContext),
      focusedIndex = _useContext4.focusedIndex,
      id = _useContext4.id,
      selectedIndex = _useContext4.selectedIndex;

  return useMemo(function () {
    return {
      focusedIndex: focusedIndex,
      id: id,
      selectedIndex: selectedIndex
    };
  }, [focusedIndex, id, selectedIndex]);
}

export { Tab, TabList, TabPanel, TabPanels, Tabs, TabsKeyboardActivation, TabsOrientation, useTabsContext };
//# sourceMappingURL=tabs.esm.esm.js.map
