Tabs.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
  3. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  4. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  5. import _typeof from "@babel/runtime/helpers/esm/typeof";
  6. import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
  7. var _excluded = ["id", "prefixCls", "className", "items", "direction", "activeKey", "defaultActiveKey", "editable", "animated", "tabPosition", "tabBarGutter", "tabBarStyle", "tabBarExtraContent", "locale", "more", "destroyInactiveTabPane", "renderTabBar", "onChange", "onTabClick", "onTabScroll", "getPopupContainer", "popupClassName", "indicator"];
  8. // Accessibility https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Tab_Role
  9. import classNames from 'classnames';
  10. import useMergedState from "rc-util/es/hooks/useMergedState";
  11. import isMobile from "rc-util/es/isMobile";
  12. import * as React from 'react';
  13. import { useEffect, useState } from 'react';
  14. import TabContext from "./TabContext";
  15. import TabNavListWrapper from "./TabNavList/Wrapper";
  16. import TabPanelList from "./TabPanelList";
  17. import useAnimateConfig from "./hooks/useAnimateConfig";
  18. /**
  19. * Should added antd:
  20. * - type
  21. *
  22. * Removed:
  23. * - onNextClick
  24. * - onPrevClick
  25. * - keyboard
  26. */
  27. // Used for accessibility
  28. var uuid = 0;
  29. var Tabs = /*#__PURE__*/React.forwardRef(function (props, ref) {
  30. var id = props.id,
  31. _props$prefixCls = props.prefixCls,
  32. prefixCls = _props$prefixCls === void 0 ? 'rc-tabs' : _props$prefixCls,
  33. className = props.className,
  34. items = props.items,
  35. direction = props.direction,
  36. activeKey = props.activeKey,
  37. defaultActiveKey = props.defaultActiveKey,
  38. editable = props.editable,
  39. animated = props.animated,
  40. _props$tabPosition = props.tabPosition,
  41. tabPosition = _props$tabPosition === void 0 ? 'top' : _props$tabPosition,
  42. tabBarGutter = props.tabBarGutter,
  43. tabBarStyle = props.tabBarStyle,
  44. tabBarExtraContent = props.tabBarExtraContent,
  45. locale = props.locale,
  46. more = props.more,
  47. destroyInactiveTabPane = props.destroyInactiveTabPane,
  48. renderTabBar = props.renderTabBar,
  49. onChange = props.onChange,
  50. onTabClick = props.onTabClick,
  51. onTabScroll = props.onTabScroll,
  52. getPopupContainer = props.getPopupContainer,
  53. popupClassName = props.popupClassName,
  54. indicator = props.indicator,
  55. restProps = _objectWithoutProperties(props, _excluded);
  56. var tabs = React.useMemo(function () {
  57. return (items || []).filter(function (item) {
  58. return item && _typeof(item) === 'object' && 'key' in item;
  59. });
  60. }, [items]);
  61. var rtl = direction === 'rtl';
  62. var mergedAnimated = useAnimateConfig(animated);
  63. // ======================== Mobile ========================
  64. var _useState = useState(false),
  65. _useState2 = _slicedToArray(_useState, 2),
  66. mobile = _useState2[0],
  67. setMobile = _useState2[1];
  68. useEffect(function () {
  69. // Only update on the client side
  70. setMobile(isMobile());
  71. }, []);
  72. // ====================== Active Key ======================
  73. var _useMergedState = useMergedState(function () {
  74. var _tabs$;
  75. return (_tabs$ = tabs[0]) === null || _tabs$ === void 0 ? void 0 : _tabs$.key;
  76. }, {
  77. value: activeKey,
  78. defaultValue: defaultActiveKey
  79. }),
  80. _useMergedState2 = _slicedToArray(_useMergedState, 2),
  81. mergedActiveKey = _useMergedState2[0],
  82. setMergedActiveKey = _useMergedState2[1];
  83. var _useState3 = useState(function () {
  84. return tabs.findIndex(function (tab) {
  85. return tab.key === mergedActiveKey;
  86. });
  87. }),
  88. _useState4 = _slicedToArray(_useState3, 2),
  89. activeIndex = _useState4[0],
  90. setActiveIndex = _useState4[1];
  91. // Reset active key if not exist anymore
  92. useEffect(function () {
  93. var newActiveIndex = tabs.findIndex(function (tab) {
  94. return tab.key === mergedActiveKey;
  95. });
  96. if (newActiveIndex === -1) {
  97. var _tabs$newActiveIndex;
  98. newActiveIndex = Math.max(0, Math.min(activeIndex, tabs.length - 1));
  99. setMergedActiveKey((_tabs$newActiveIndex = tabs[newActiveIndex]) === null || _tabs$newActiveIndex === void 0 ? void 0 : _tabs$newActiveIndex.key);
  100. }
  101. setActiveIndex(newActiveIndex);
  102. }, [tabs.map(function (tab) {
  103. return tab.key;
  104. }).join('_'), mergedActiveKey, activeIndex]);
  105. // ===================== Accessibility ====================
  106. var _useMergedState3 = useMergedState(null, {
  107. value: id
  108. }),
  109. _useMergedState4 = _slicedToArray(_useMergedState3, 2),
  110. mergedId = _useMergedState4[0],
  111. setMergedId = _useMergedState4[1];
  112. // Async generate id to avoid ssr mapping failed
  113. useEffect(function () {
  114. if (!id) {
  115. setMergedId("rc-tabs-".concat(process.env.NODE_ENV === 'test' ? 'test' : uuid));
  116. uuid += 1;
  117. }
  118. }, []);
  119. // ======================== Events ========================
  120. function onInternalTabClick(key, e) {
  121. onTabClick === null || onTabClick === void 0 || onTabClick(key, e);
  122. var isActiveChanged = key !== mergedActiveKey;
  123. setMergedActiveKey(key);
  124. if (isActiveChanged) {
  125. onChange === null || onChange === void 0 || onChange(key);
  126. }
  127. }
  128. // ======================== Render ========================
  129. var sharedProps = {
  130. id: mergedId,
  131. activeKey: mergedActiveKey,
  132. animated: mergedAnimated,
  133. tabPosition: tabPosition,
  134. rtl: rtl,
  135. mobile: mobile
  136. };
  137. var tabNavBarProps = _objectSpread(_objectSpread({}, sharedProps), {}, {
  138. editable: editable,
  139. locale: locale,
  140. more: more,
  141. tabBarGutter: tabBarGutter,
  142. onTabClick: onInternalTabClick,
  143. onTabScroll: onTabScroll,
  144. extra: tabBarExtraContent,
  145. style: tabBarStyle,
  146. panes: null,
  147. getPopupContainer: getPopupContainer,
  148. popupClassName: popupClassName,
  149. indicator: indicator
  150. });
  151. return /*#__PURE__*/React.createElement(TabContext.Provider, {
  152. value: {
  153. tabs: tabs,
  154. prefixCls: prefixCls
  155. }
  156. }, /*#__PURE__*/React.createElement("div", _extends({
  157. ref: ref,
  158. id: id,
  159. className: classNames(prefixCls, "".concat(prefixCls, "-").concat(tabPosition), _defineProperty(_defineProperty(_defineProperty({}, "".concat(prefixCls, "-mobile"), mobile), "".concat(prefixCls, "-editable"), editable), "".concat(prefixCls, "-rtl"), rtl), className)
  160. }, restProps), /*#__PURE__*/React.createElement(TabNavListWrapper, _extends({}, tabNavBarProps, {
  161. renderTabBar: renderTabBar
  162. })), /*#__PURE__*/React.createElement(TabPanelList, _extends({
  163. destroyInactiveTabPane: destroyInactiveTabPane
  164. }, sharedProps, {
  165. animated: mergedAnimated
  166. }))));
  167. });
  168. if (process.env.NODE_ENV !== 'production') {
  169. Tabs.displayName = 'Tabs';
  170. }
  171. export default Tabs;