@bento-core/tab 1.0.0-c3dc.1 → 1.0.0-c3dc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Tabs.js CHANGED
@@ -4,26 +4,155 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
7
+ var _react = _interopRequireWildcard(require("react"));
8
8
  var _core = require("@material-ui/core");
9
9
  var _toolTip = _interopRequireDefault(require("@bento-core/tool-tip"));
10
10
  var _defaultTheme = require("./defaultTheme");
11
+ var _moreVertical = _interopRequireDefault(require("./assets/icons/more-vertical.svg"));
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
12
15
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
13
16
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
14
17
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
15
18
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
16
19
  function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
17
20
  function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
21
+ // Calculate default window width for SSR (ensures max tabs)
22
+ const getDefaultWindowWidth = responsiveBreakpoints => {
23
+ if (!responsiveBreakpoints || !Array.isArray(responsiveBreakpoints.breakpoints) || responsiveBreakpoints.breakpoints.length === 0) {
24
+ return 1800; // Fallback if no config provided
25
+ }
26
+ // Use width above the highest breakpoint to ensure default tab limit
27
+ const {
28
+ breakpoints
29
+ } = responsiveBreakpoints;
30
+ const highestBreakpoint = breakpoints[breakpoints.length - 1];
31
+ return highestBreakpoint.maxWidth + 100;
32
+ };
18
33
  const TabItems = _ref => {
19
34
  let {
20
35
  tabItems,
21
36
  handleTabChange,
22
37
  currentTab,
23
38
  orientation,
24
- customTheme = {}
39
+ customTheme = {},
40
+ maxVisibleTabs = 6,
41
+ enableGrouping = false,
42
+ responsiveBreakpoints = null
25
43
  } = _ref;
26
- const getTabLalbel = _ref2 => {
44
+ const [currentGroup, setCurrentGroup] = (0, _react.useState)(0);
45
+ const [showMorePopup, setShowMorePopup] = (0, _react.useState)(false);
46
+ const [moreButtonAnchor, setMoreButtonAnchor] = (0, _react.useState)(null);
47
+ const [windowWidth, setWindowWidth] = (0, _react.useState)(typeof window !== 'undefined' ? window.innerWidth : getDefaultWindowWidth(responsiveBreakpoints));
48
+
49
+ // Calculate tab limit based on screen width breakpoints
50
+ const getTabLimitByWidth = width => {
51
+ if (!responsiveBreakpoints) {
52
+ // Fallback to original hardcoded values if no config provided
53
+ if (width < 1250) return 2;
54
+ if (width < 1400) return 3;
55
+ if (width < 1550) return 4;
56
+ if (width < 1700) return 5;
57
+ return 6; // >= 1700px
58
+ }
59
+
60
+ // Use configuration-based breakpoints
61
+ for (let i = 0; i < responsiveBreakpoints.breakpoints.length; i += 1) {
62
+ const {
63
+ maxWidth,
64
+ tabLimit
65
+ } = responsiveBreakpoints.breakpoints[i];
66
+ if (width <= maxWidth) {
67
+ return tabLimit;
68
+ }
69
+ }
70
+ return responsiveBreakpoints.defaultTabLimit;
71
+ };
72
+
73
+ // Grouping logic with responsive breakpoints
74
+ const tabLimit = enableGrouping ? getTabLimitByWidth(windowWidth) : maxVisibleTabs;
75
+ const shouldShowMoreButton = enableGrouping && tabItems.length > tabLimit;
76
+
77
+ // Window resize listener for responsive breakpoints
78
+ (0, _react.useEffect)(() => {
79
+ if (!enableGrouping || typeof window === 'undefined') {
80
+ return undefined;
81
+ }
82
+ const handleResize = () => {
83
+ const newWidth = window.innerWidth;
84
+ setWindowWidth(newWidth);
85
+ };
86
+ window.addEventListener('resize', handleResize);
87
+ return () => {
88
+ window.removeEventListener('resize', handleResize);
89
+ };
90
+ }, [enableGrouping]);
91
+
92
+ // Consolidated effect: handle tab limit changes and active tab group recalculation
93
+ (0, _react.useEffect)(() => {
94
+ if (!enableGrouping) {
95
+ return;
96
+ }
97
+ const newActiveTabGroup = Math.floor(currentTab / tabLimit);
98
+ if (newActiveTabGroup !== currentGroup) {
99
+ setCurrentGroup(newActiveTabGroup);
100
+ }
101
+ }, [tabLimit, currentTab, currentGroup, enableGrouping]);
102
+
103
+ // Get visible tabs for current group
104
+ const getVisibleTabs = () => {
105
+ if (!enableGrouping) {
106
+ return tabItems;
107
+ }
108
+ const startIndex = currentGroup * tabLimit;
109
+ const endIndex = Math.min(startIndex + tabLimit, tabItems.length);
110
+ return tabItems.slice(startIndex, endIndex);
111
+ };
112
+
113
+ // Get popup tabs with wrap-around logic (memoized for performance)
114
+ const popupTabs = (0, _react.useMemo)(() => {
115
+ if (!enableGrouping || !shouldShowMoreButton) {
116
+ return [];
117
+ }
118
+ const visibleStart = currentGroup * tabLimit;
119
+ const visibleEnd = Math.min(visibleStart + tabLimit, tabItems.length);
120
+
121
+ // Create hidden tabs with their original indices to avoid O(n²) findIndex
122
+ const hiddenTabsWithIndex = [];
123
+
124
+ // Add tabs after visible range
125
+ for (let i = visibleEnd; i < tabItems.length; i += 1) {
126
+ hiddenTabsWithIndex.push({
127
+ tab: tabItems[i],
128
+ originalIndex: i
129
+ });
130
+ }
131
+
132
+ // Add tabs before visible range (wrap-around)
133
+ for (let i = 0; i < visibleStart; i += 1) {
134
+ hiddenTabsWithIndex.push({
135
+ tab: tabItems[i],
136
+ originalIndex: i
137
+ });
138
+ }
139
+ return hiddenTabsWithIndex;
140
+ }, [enableGrouping, shouldShowMoreButton, currentGroup, tabLimit, tabItems]);
141
+ const handleMoreButtonClick = event => {
142
+ setMoreButtonAnchor(event.currentTarget);
143
+ setShowMorePopup(true);
144
+ };
145
+ const handlePopupClose = () => {
146
+ setShowMorePopup(false);
147
+ setMoreButtonAnchor(null);
148
+ };
149
+ const handlePopupTabClick = tabIndex => {
150
+ const newGroup = Math.floor(tabIndex / tabLimit);
151
+ setCurrentGroup(newGroup);
152
+ handleTabChange(null, tabIndex);
153
+ handlePopupClose();
154
+ };
155
+ const getTabLabel = _ref2 => {
27
156
  let {
28
157
  name,
29
158
  count,
@@ -50,42 +179,103 @@ const TabItems = _ref => {
50
179
  }
51
180
  }, count));
52
181
  };
53
- const TABs = tabItems.map((tab, index) => tab.hasToolTip ? /*#__PURE__*/_react.default.createElement(_toolTip.default, _extends({}, tab.tooltipStyles, {
54
- title: tab.toolTipText || '.',
55
- arrow: true,
56
- placement: "top"
57
- }), /*#__PURE__*/_react.default.createElement(_core.Tab, {
58
- index: index,
59
- label: getTabLalbel(_objectSpread(_objectSpread({}, tab), {}, {
60
- index
61
- })),
62
- key: index,
63
- className: tab.clsName,
64
- disableRipple: true
65
- })) : /*#__PURE__*/_react.default.createElement(_core.Tab, {
66
- index: index,
67
- label: getTabLalbel(_objectSpread(_objectSpread({}, tab), {}, {
68
- index
69
- })),
70
- key: index,
71
- className: tab.clsName,
72
- disableRipple: true
73
- }));
182
+ const visibleTabs = getVisibleTabs();
183
+ const TABs = visibleTabs.map((tab, visibleIndex) => {
184
+ // Calculate the actual tab index in the full tabItems array
185
+ const actualIndex = enableGrouping ? currentGroup * tabLimit + visibleIndex : visibleIndex;
186
+ return tab.hasToolTip ? /*#__PURE__*/_react.default.createElement(_toolTip.default, _extends({}, tab.tooltipStyles, {
187
+ title: tab.toolTipText || '.',
188
+ arrow: true,
189
+ placement: "top",
190
+ key: actualIndex
191
+ }), /*#__PURE__*/_react.default.createElement(_core.Tab, {
192
+ index: actualIndex,
193
+ label: getTabLabel(_objectSpread(_objectSpread({}, tab), {}, {
194
+ index: actualIndex
195
+ })),
196
+ className: tab.clsName,
197
+ disableRipple: true
198
+ })) : /*#__PURE__*/_react.default.createElement(_core.Tab, {
199
+ index: actualIndex,
200
+ label: getTabLabel(_objectSpread(_objectSpread({}, tab), {}, {
201
+ index: actualIndex
202
+ })),
203
+ key: actualIndex,
204
+ className: tab.clsName,
205
+ disableRipple: true
206
+ });
207
+ });
208
+
209
+ // Add More button if needed
210
+ if (shouldShowMoreButton) {
211
+ const hiddenTabsCount = popupTabs.length;
212
+ TABs.push( /*#__PURE__*/_react.default.createElement(_core.Button, {
213
+ key: "more-button",
214
+ onClick: handleMoreButtonClick,
215
+ className: "more-button"
216
+ }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("img", {
217
+ src: _moreVertical.default,
218
+ alt: "More options"
219
+ }), "More(".concat(hiddenTabsCount, ")"))));
220
+ }
221
+
222
+ // Adjust currentTab value for visible tabs when grouping is enabled
223
+ const adjustedCurrentTab = enableGrouping ? currentTab - currentGroup * tabLimit : currentTab;
74
224
  const themeConfig = (0, _core.createTheme)({
75
225
  overrides: _objectSpread(_objectSpread({}, (0, _defaultTheme.defaultTheme)()), customTheme)
76
226
  });
77
227
  return /*#__PURE__*/_react.default.createElement(_core.ThemeProvider, {
78
228
  theme: themeConfig
229
+ }, /*#__PURE__*/_react.default.createElement("div", {
230
+ style: {
231
+ position: 'relative'
232
+ }
79
233
  }, /*#__PURE__*/_react.default.createElement(_core.Tabs, {
80
- onChange: (event, value) => handleTabChange(event, value),
81
- value: currentTab,
234
+ onChange: (event, value) => {
235
+ // Convert relative position to actual tab index when grouping is enabled
236
+ const actualTabIndex = enableGrouping ? currentGroup * tabLimit + value : value;
237
+ handleTabChange(event, actualTabIndex);
238
+ },
239
+ value: adjustedCurrentTab,
82
240
  TabIndicatorProps: {
83
241
  style: {
84
242
  background: 'none'
85
243
  }
86
244
  },
87
245
  orientation: orientation
88
- }, TABs));
246
+ }, TABs), shouldShowMoreButton && /*#__PURE__*/_react.default.createElement(_core.Popover, {
247
+ open: showMorePopup,
248
+ anchorEl: moreButtonAnchor,
249
+ onClose: handlePopupClose,
250
+ anchorOrigin: {
251
+ vertical: 'bottom',
252
+ horizontal: 'center'
253
+ },
254
+ transformOrigin: {
255
+ vertical: 'top',
256
+ horizontal: 'center'
257
+ },
258
+ style: {
259
+ marginTop: '10px'
260
+ }
261
+ }, /*#__PURE__*/_react.default.createElement(_core.List, {
262
+ className: "popover-list"
263
+ }, popupTabs.map(_ref3 => {
264
+ let {
265
+ tab,
266
+ originalIndex
267
+ } = _ref3;
268
+ return /*#__PURE__*/_react.default.createElement(_core.ListItem, {
269
+ key: originalIndex,
270
+ button: true,
271
+ onClick: () => handlePopupTabClick(originalIndex),
272
+ className: "popover-list-item"
273
+ }, /*#__PURE__*/_react.default.createElement("span", {
274
+ className: "popover-tab-name"
275
+ }, tab.name), /*#__PURE__*/_react.default.createElement("span", {
276
+ className: "popover-tab-count"
277
+ }, tab.count || ''));
278
+ })))));
89
279
  };
90
280
  var _default = TabItems;
91
281
  exports.default = _default;
@@ -0,0 +1,17 @@
1
+ <svg width="4" height="16" viewBox="0 0 4 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
3
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
4
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
5
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
6
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
7
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
8
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
9
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
10
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
11
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
12
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
13
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
14
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
15
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
16
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
17
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bento-core/tab",
3
- "version": "1.0.0-c3dc.1",
3
+ "version": "1.0.0-c3dc.2",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "peerDependencies": {
16
16
  "@material-ui/core": "^4.12.4",
17
- "@bento-core/tool-tip": "^0.2.0",
17
+ "@bento-core/tool-tip": "1.0.0-c3dc.0",
18
18
  "react": "^17.0.2",
19
19
  "react-dom": "^17.0.0",
20
20
  "react-redux": "^7.2.1"
package/src/Tabs.js CHANGED
@@ -1,12 +1,32 @@
1
- import React from 'react';
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
2
  import {
3
3
  Tab,
4
4
  Tabs,
5
5
  createTheme,
6
6
  ThemeProvider,
7
+ Button,
8
+ Popover,
9
+ List,
10
+ ListItem,
7
11
  } from '@material-ui/core';
8
12
  import ToolTip from '@bento-core/tool-tip';
9
13
  import { defaultTheme } from './defaultTheme';
14
+ import MoreVerticalIcon from './assets/icons/more-vertical.svg';
15
+
16
+ // Calculate default window width for SSR (ensures max tabs)
17
+ const getDefaultWindowWidth = (responsiveBreakpoints) => {
18
+ if (
19
+ !responsiveBreakpoints
20
+ || !Array.isArray(responsiveBreakpoints.breakpoints)
21
+ || responsiveBreakpoints.breakpoints.length === 0
22
+ ) {
23
+ return 1800; // Fallback if no config provided
24
+ }
25
+ // Use width above the highest breakpoint to ensure default tab limit
26
+ const { breakpoints } = responsiveBreakpoints;
27
+ const highestBreakpoint = breakpoints[breakpoints.length - 1];
28
+ return highestBreakpoint.maxWidth + 100;
29
+ };
10
30
 
11
31
  const TabItems = ({
12
32
  tabItems,
@@ -14,8 +34,122 @@ const TabItems = ({
14
34
  currentTab,
15
35
  orientation,
16
36
  customTheme = {},
37
+ maxVisibleTabs = 6,
38
+ enableGrouping = false,
39
+ responsiveBreakpoints = null,
17
40
  }) => {
18
- const getTabLalbel = ({
41
+ const [currentGroup, setCurrentGroup] = useState(0);
42
+ const [showMorePopup, setShowMorePopup] = useState(false);
43
+ const [moreButtonAnchor, setMoreButtonAnchor] = useState(null);
44
+ const [windowWidth, setWindowWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : getDefaultWindowWidth(responsiveBreakpoints));
45
+
46
+ // Calculate tab limit based on screen width breakpoints
47
+ const getTabLimitByWidth = (width) => {
48
+ if (!responsiveBreakpoints) {
49
+ // Fallback to original hardcoded values if no config provided
50
+ if (width < 1250) return 2;
51
+ if (width < 1400) return 3;
52
+ if (width < 1550) return 4;
53
+ if (width < 1700) return 5;
54
+ return 6; // >= 1700px
55
+ }
56
+
57
+ // Use configuration-based breakpoints
58
+ for (let i = 0; i < responsiveBreakpoints.breakpoints.length; i += 1) {
59
+ const { maxWidth, tabLimit } = responsiveBreakpoints.breakpoints[i];
60
+ if (width <= maxWidth) {
61
+ return tabLimit;
62
+ }
63
+ }
64
+ return responsiveBreakpoints.defaultTabLimit;
65
+ };
66
+
67
+ // Grouping logic with responsive breakpoints
68
+ const tabLimit = enableGrouping ? getTabLimitByWidth(windowWidth) : maxVisibleTabs;
69
+ const shouldShowMoreButton = enableGrouping && tabItems.length > tabLimit;
70
+
71
+ // Window resize listener for responsive breakpoints
72
+ useEffect(() => {
73
+ if (!enableGrouping || typeof window === 'undefined') {
74
+ return undefined;
75
+ }
76
+
77
+ const handleResize = () => {
78
+ const newWidth = window.innerWidth;
79
+ setWindowWidth(newWidth);
80
+ };
81
+
82
+ window.addEventListener('resize', handleResize);
83
+ return () => {
84
+ window.removeEventListener('resize', handleResize);
85
+ };
86
+ }, [enableGrouping]);
87
+
88
+ // Consolidated effect: handle tab limit changes and active tab group recalculation
89
+ useEffect(() => {
90
+ if (!enableGrouping) {
91
+ return;
92
+ }
93
+
94
+ const newActiveTabGroup = Math.floor(currentTab / tabLimit);
95
+ if (newActiveTabGroup !== currentGroup) {
96
+ setCurrentGroup(newActiveTabGroup);
97
+ }
98
+ }, [tabLimit, currentTab, currentGroup, enableGrouping]);
99
+
100
+ // Get visible tabs for current group
101
+ const getVisibleTabs = () => {
102
+ if (!enableGrouping) {
103
+ return tabItems;
104
+ }
105
+ const startIndex = currentGroup * tabLimit;
106
+ const endIndex = Math.min(startIndex + tabLimit, tabItems.length);
107
+ return tabItems.slice(startIndex, endIndex);
108
+ };
109
+
110
+ // Get popup tabs with wrap-around logic (memoized for performance)
111
+ const popupTabs = useMemo(() => {
112
+ if (!enableGrouping || !shouldShowMoreButton) {
113
+ return [];
114
+ }
115
+
116
+ const visibleStart = currentGroup * tabLimit;
117
+ const visibleEnd = Math.min(visibleStart + tabLimit, tabItems.length);
118
+
119
+ // Create hidden tabs with their original indices to avoid O(n²) findIndex
120
+ const hiddenTabsWithIndex = [];
121
+
122
+ // Add tabs after visible range
123
+ for (let i = visibleEnd; i < tabItems.length; i += 1) {
124
+ hiddenTabsWithIndex.push({ tab: tabItems[i], originalIndex: i });
125
+ }
126
+
127
+ // Add tabs before visible range (wrap-around)
128
+ for (let i = 0; i < visibleStart; i += 1) {
129
+ hiddenTabsWithIndex.push({ tab: tabItems[i], originalIndex: i });
130
+ }
131
+
132
+ return hiddenTabsWithIndex;
133
+ }, [enableGrouping, shouldShowMoreButton, currentGroup, tabLimit, tabItems]);
134
+
135
+ const handleMoreButtonClick = (event) => {
136
+ setMoreButtonAnchor(event.currentTarget);
137
+ setShowMorePopup(true);
138
+ };
139
+
140
+ const handlePopupClose = () => {
141
+ setShowMorePopup(false);
142
+ setMoreButtonAnchor(null);
143
+ };
144
+
145
+ const handlePopupTabClick = (tabIndex) => {
146
+ const newGroup = Math.floor(tabIndex / tabLimit);
147
+ setCurrentGroup(newGroup);
148
+ handleTabChange(null, tabIndex);
149
+ handlePopupClose();
150
+ };
151
+
152
+ const getTabLabel = ({
19
153
  name, count, clsName, index,
20
154
  }) => (
21
155
  <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
@@ -35,17 +169,20 @@ const TabItems = ({
35
169
  </div>
36
170
  );
37
171
 
38
- const TABs = tabItems.map((tab, index) => (
172
+ const visibleTabs = getVisibleTabs();
173
+
174
+ const TABs = visibleTabs.map((tab, visibleIndex) => {
175
+ // Calculate the actual tab index in the full tabItems array
176
+ const actualIndex = enableGrouping
177
+ ? (currentGroup * tabLimit) + visibleIndex
178
+ : visibleIndex;
39
179
 
40
- tab.hasToolTip
180
+ return tab.hasToolTip
41
181
  ? (
42
- <ToolTip {...tab.tooltipStyles} title={tab.toolTipText || '.'} arrow placement="top">
182
+ <ToolTip {...tab.tooltipStyles} title={tab.toolTipText || '.'} arrow placement="top" key={actualIndex}>
43
183
  <Tab
44
- index={index}
45
- label={
46
- getTabLalbel({ ...tab, index })
47
- }
48
- key={index}
184
+ index={actualIndex}
185
+ label={getTabLabel({ ...tab, index: actualIndex })}
49
186
  className={tab.clsName}
50
187
  disableRipple
51
188
  />
@@ -53,29 +190,92 @@ const TabItems = ({
53
190
  )
54
191
  : (
55
192
  <Tab
56
- index={index}
57
- label={
58
- getTabLalbel({ ...tab, index })
59
- }
60
- key={index}
193
+ index={actualIndex}
194
+ label={getTabLabel({ ...tab, index: actualIndex })}
195
+ key={actualIndex}
61
196
  className={tab.clsName}
62
197
  disableRipple
63
198
  />
64
- )
199
+ );
200
+ });
201
+
202
+ // Add More button if needed
203
+ if (shouldShowMoreButton) {
204
+ const hiddenTabsCount = popupTabs.length;
205
+ TABs.push(
206
+ <Button
207
+ key="more-button"
208
+ onClick={handleMoreButtonClick}
209
+ className="more-button"
210
+ >
211
+ <span>
212
+ <img src={MoreVerticalIcon} alt="More options" />
213
+ {`More(${hiddenTabsCount})`}
214
+ </span>
215
+ </Button>,
216
+ );
217
+ }
65
218
 
66
- ));
219
+ // Adjust currentTab value for visible tabs when grouping is enabled
220
+ const adjustedCurrentTab = enableGrouping
221
+ ? currentTab - (currentGroup * tabLimit)
222
+ : currentTab;
67
223
 
68
224
  const themeConfig = createTheme({ overrides: { ...defaultTheme(), ...customTheme } });
69
225
  return (
70
226
  <ThemeProvider theme={themeConfig}>
71
- <Tabs
72
- onChange={(event, value) => handleTabChange(event, value)}
73
- value={currentTab}
74
- TabIndicatorProps={{ style: { background: 'none' } }}
75
- orientation={orientation}
76
- >
77
- {TABs}
78
- </Tabs>
227
+ <div style={{ position: 'relative' }}>
228
+ <Tabs
229
+ onChange={(event, value) => {
230
+ // Convert relative position to actual tab index when grouping is enabled
231
+ const actualTabIndex = enableGrouping
232
+ ? (currentGroup * tabLimit) + value
233
+ : value;
234
+ handleTabChange(event, actualTabIndex);
235
+ }}
236
+ value={adjustedCurrentTab}
237
+ TabIndicatorProps={{ style: { background: 'none' } }}
238
+ orientation={orientation}
239
+ >
240
+ {TABs}
241
+ </Tabs>
242
+
243
+ {/* More button popup */}
244
+ {shouldShowMoreButton && (
245
+ <Popover
246
+ open={showMorePopup}
247
+ anchorEl={moreButtonAnchor}
248
+ onClose={handlePopupClose}
249
+ anchorOrigin={{
250
+ vertical: 'bottom',
251
+ horizontal: 'center',
252
+ }}
253
+ transformOrigin={{
254
+ vertical: 'top',
255
+ horizontal: 'center',
256
+ }}
257
+ style={{ marginTop: '10px' }}
258
+ >
259
+ <List className="popover-list">
260
+ {popupTabs.map(({ tab, originalIndex }) => (
261
+ <ListItem
262
+ key={originalIndex}
263
+ button
264
+ onClick={() => handlePopupTabClick(originalIndex)}
265
+ className="popover-list-item"
266
+ >
267
+ <span className="popover-tab-name">
268
+ {tab.name}
269
+ </span>
270
+ <span className="popover-tab-count">
271
+ {tab.count || ''}
272
+ </span>
273
+ </ListItem>
274
+ ))}
275
+ </List>
276
+ </Popover>
277
+ )}
278
+ </div>
79
279
  </ThemeProvider>
80
280
  );
81
281
  };
@@ -0,0 +1,17 @@
1
+ <svg width="4" height="16" viewBox="0 0 4 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
3
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
4
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
5
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
6
+ <circle cx="1.8811" cy="2.4519" r="1.84937" fill="black"/>
7
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
8
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
9
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
10
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
11
+ <circle cx="1.8811" cy="7.99976" r="1.84937" fill="black"/>
12
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
13
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
14
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
15
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
16
+ <circle cx="1.8811" cy="13.5481" r="1.84937" fill="black"/>
17
+ </svg>