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

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,161 @@ 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
+ const tab = tabItems[i];
127
+ if (tab) {
128
+ hiddenTabsWithIndex.push({
129
+ tab,
130
+ originalIndex: i
131
+ });
132
+ }
133
+ }
134
+
135
+ // Add tabs before visible range (wrap-around)
136
+ for (let i = 0; i < visibleStart; i += 1) {
137
+ const tab = tabItems[i];
138
+ if (tab) {
139
+ hiddenTabsWithIndex.push({
140
+ tab,
141
+ originalIndex: i
142
+ });
143
+ }
144
+ }
145
+ return hiddenTabsWithIndex;
146
+ }, [enableGrouping, shouldShowMoreButton, currentGroup, tabLimit, tabItems]);
147
+ const handleMoreButtonClick = event => {
148
+ setMoreButtonAnchor(event.currentTarget);
149
+ setShowMorePopup(true);
150
+ };
151
+ const handlePopupClose = () => {
152
+ setShowMorePopup(false);
153
+ setMoreButtonAnchor(null);
154
+ };
155
+ const handlePopupTabClick = tabIndex => {
156
+ const newGroup = Math.floor(tabIndex / tabLimit);
157
+ setCurrentGroup(newGroup);
158
+ handleTabChange(null, tabIndex);
159
+ handlePopupClose();
160
+ };
161
+ const getTabLabel = _ref2 => {
27
162
  let {
28
163
  name,
29
164
  count,
@@ -50,42 +185,106 @@ const TabItems = _ref => {
50
185
  }
51
186
  }, count));
52
187
  };
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
- }));
188
+ const visibleTabs = getVisibleTabs();
189
+ const TABs = visibleTabs.map((tab, visibleIndex) => {
190
+ // Calculate the actual tab index in the full tabItems array
191
+ const actualIndex = enableGrouping ? currentGroup * tabLimit + visibleIndex : visibleIndex;
192
+ return tab.hasToolTip ? /*#__PURE__*/_react.default.createElement(_toolTip.default, _extends({}, tab.tooltipStyles, {
193
+ title: tab.toolTipText || '.',
194
+ arrow: true,
195
+ placement: "top",
196
+ key: actualIndex
197
+ }), /*#__PURE__*/_react.default.createElement(_core.Tab, {
198
+ index: actualIndex,
199
+ label: getTabLabel(_objectSpread(_objectSpread({}, tab), {}, {
200
+ index: actualIndex
201
+ })),
202
+ className: tab.clsName,
203
+ disableRipple: true
204
+ })) : /*#__PURE__*/_react.default.createElement(_core.Tab, {
205
+ index: actualIndex,
206
+ label: getTabLabel(_objectSpread(_objectSpread({}, tab), {}, {
207
+ index: actualIndex
208
+ })),
209
+ key: actualIndex,
210
+ className: tab.clsName,
211
+ disableRipple: true
212
+ });
213
+ });
214
+
215
+ // Add More button if needed
216
+ if (shouldShowMoreButton) {
217
+ const hiddenTabsCount = popupTabs.length;
218
+ TABs.push( /*#__PURE__*/_react.default.createElement(_core.Button, {
219
+ key: "more-button",
220
+ onClick: handleMoreButtonClick,
221
+ className: "more-button"
222
+ }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("img", {
223
+ src: _moreVertical.default,
224
+ alt: "More options"
225
+ }), "More(".concat(hiddenTabsCount, ")"))));
226
+ }
227
+
228
+ // Adjust currentTab value for visible tabs when grouping is enabled
229
+ const adjustedCurrentTab = enableGrouping ? currentTab - currentGroup * tabLimit : currentTab;
74
230
  const themeConfig = (0, _core.createTheme)({
75
231
  overrides: _objectSpread(_objectSpread({}, (0, _defaultTheme.defaultTheme)()), customTheme)
76
232
  });
77
233
  return /*#__PURE__*/_react.default.createElement(_core.ThemeProvider, {
78
234
  theme: themeConfig
235
+ }, /*#__PURE__*/_react.default.createElement("div", {
236
+ style: {
237
+ position: 'relative'
238
+ }
79
239
  }, /*#__PURE__*/_react.default.createElement(_core.Tabs, {
80
- onChange: (event, value) => handleTabChange(event, value),
81
- value: currentTab,
240
+ onChange: (event, value) => {
241
+ // Convert relative position to actual tab index when grouping is enabled
242
+ const actualTabIndex = enableGrouping ? currentGroup * tabLimit + value : value;
243
+ handleTabChange(event, actualTabIndex);
244
+ },
245
+ value: adjustedCurrentTab,
82
246
  TabIndicatorProps: {
83
247
  style: {
84
248
  background: 'none'
85
249
  }
86
250
  },
87
251
  orientation: orientation
88
- }, TABs));
252
+ }, TABs), shouldShowMoreButton && /*#__PURE__*/_react.default.createElement(_core.Popover, {
253
+ open: showMorePopup,
254
+ anchorEl: moreButtonAnchor,
255
+ onClose: handlePopupClose,
256
+ anchorOrigin: {
257
+ vertical: 'bottom',
258
+ horizontal: 'center'
259
+ },
260
+ transformOrigin: {
261
+ vertical: 'top',
262
+ horizontal: 'center'
263
+ },
264
+ style: {
265
+ marginTop: '10px'
266
+ }
267
+ }, /*#__PURE__*/_react.default.createElement(_core.List, {
268
+ className: "popover-list"
269
+ }, popupTabs.map(_ref3 => {
270
+ let {
271
+ tab,
272
+ originalIndex
273
+ } = _ref3;
274
+ if (!tab || !tab.name) {
275
+ return null;
276
+ }
277
+ return /*#__PURE__*/_react.default.createElement(_core.ListItem, {
278
+ key: originalIndex,
279
+ button: true,
280
+ onClick: () => handlePopupTabClick(originalIndex),
281
+ className: "popover-list-item"
282
+ }, /*#__PURE__*/_react.default.createElement("span", {
283
+ className: "popover-tab-name"
284
+ }, tab.name), /*#__PURE__*/_react.default.createElement("span", {
285
+ className: "popover-tab-count"
286
+ }, tab.count || ''));
287
+ })))));
89
288
  };
90
289
  var _default = TabItems;
91
290
  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.3",
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,128 @@ 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
+ const tab = tabItems[i];
125
+ if (tab) {
126
+ hiddenTabsWithIndex.push({ tab, originalIndex: i });
127
+ }
128
+ }
129
+
130
+ // Add tabs before visible range (wrap-around)
131
+ for (let i = 0; i < visibleStart; i += 1) {
132
+ const tab = tabItems[i];
133
+ if (tab) {
134
+ hiddenTabsWithIndex.push({ tab, originalIndex: i });
135
+ }
136
+ }
137
+
138
+ return hiddenTabsWithIndex;
139
+ }, [enableGrouping, shouldShowMoreButton, currentGroup, tabLimit, tabItems]);
140
+
141
+ const handleMoreButtonClick = (event) => {
142
+ setMoreButtonAnchor(event.currentTarget);
143
+ setShowMorePopup(true);
144
+ };
145
+
146
+ const handlePopupClose = () => {
147
+ setShowMorePopup(false);
148
+ setMoreButtonAnchor(null);
149
+ };
150
+
151
+ const handlePopupTabClick = (tabIndex) => {
152
+ const newGroup = Math.floor(tabIndex / tabLimit);
153
+ setCurrentGroup(newGroup);
154
+ handleTabChange(null, tabIndex);
155
+ handlePopupClose();
156
+ };
157
+
158
+ const getTabLabel = ({
19
159
  name, count, clsName, index,
20
160
  }) => (
21
161
  <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
@@ -35,17 +175,20 @@ const TabItems = ({
35
175
  </div>
36
176
  );
37
177
 
38
- const TABs = tabItems.map((tab, index) => (
178
+ const visibleTabs = getVisibleTabs();
39
179
 
40
- tab.hasToolTip
180
+ const TABs = visibleTabs.map((tab, visibleIndex) => {
181
+ // Calculate the actual tab index in the full tabItems array
182
+ const actualIndex = enableGrouping
183
+ ? (currentGroup * tabLimit) + visibleIndex
184
+ : visibleIndex;
185
+
186
+ return tab.hasToolTip
41
187
  ? (
42
- <ToolTip {...tab.tooltipStyles} title={tab.toolTipText || '.'} arrow placement="top">
188
+ <ToolTip {...tab.tooltipStyles} title={tab.toolTipText || '.'} arrow placement="top" key={actualIndex}>
43
189
  <Tab
44
- index={index}
45
- label={
46
- getTabLalbel({ ...tab, index })
47
- }
48
- key={index}
190
+ index={actualIndex}
191
+ label={getTabLabel({ ...tab, index: actualIndex })}
49
192
  className={tab.clsName}
50
193
  disableRipple
51
194
  />
@@ -53,29 +196,97 @@ const TabItems = ({
53
196
  )
54
197
  : (
55
198
  <Tab
56
- index={index}
57
- label={
58
- getTabLalbel({ ...tab, index })
59
- }
60
- key={index}
199
+ index={actualIndex}
200
+ label={getTabLabel({ ...tab, index: actualIndex })}
201
+ key={actualIndex}
61
202
  className={tab.clsName}
62
203
  disableRipple
63
204
  />
64
- )
205
+ );
206
+ });
65
207
 
66
- ));
208
+ // Add More button if needed
209
+ if (shouldShowMoreButton) {
210
+ const hiddenTabsCount = popupTabs.length;
211
+ TABs.push(
212
+ <Button
213
+ key="more-button"
214
+ onClick={handleMoreButtonClick}
215
+ className="more-button"
216
+ >
217
+ <span>
218
+ <img src={MoreVerticalIcon} alt="More options" />
219
+ {`More(${hiddenTabsCount})`}
220
+ </span>
221
+ </Button>,
222
+ );
223
+ }
224
+
225
+ // Adjust currentTab value for visible tabs when grouping is enabled
226
+ const adjustedCurrentTab = enableGrouping
227
+ ? currentTab - (currentGroup * tabLimit)
228
+ : currentTab;
67
229
 
68
230
  const themeConfig = createTheme({ overrides: { ...defaultTheme(), ...customTheme } });
69
231
  return (
70
232
  <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>
233
+ <div style={{ position: 'relative' }}>
234
+ <Tabs
235
+ onChange={(event, value) => {
236
+ // Convert relative position to actual tab index when grouping is enabled
237
+ const actualTabIndex = enableGrouping
238
+ ? (currentGroup * tabLimit) + value
239
+ : value;
240
+ handleTabChange(event, actualTabIndex);
241
+ }}
242
+ value={adjustedCurrentTab}
243
+ TabIndicatorProps={{ style: { background: 'none' } }}
244
+ orientation={orientation}
245
+ >
246
+ {TABs}
247
+ </Tabs>
248
+
249
+ {/* More button popup */}
250
+ {shouldShowMoreButton && (
251
+ <Popover
252
+ open={showMorePopup}
253
+ anchorEl={moreButtonAnchor}
254
+ onClose={handlePopupClose}
255
+ anchorOrigin={{
256
+ vertical: 'bottom',
257
+ horizontal: 'center',
258
+ }}
259
+ transformOrigin={{
260
+ vertical: 'top',
261
+ horizontal: 'center',
262
+ }}
263
+ style={{ marginTop: '10px' }}
264
+ >
265
+ <List className="popover-list">
266
+ {popupTabs.map(({ tab, originalIndex }) => {
267
+ if (!tab || !tab.name) {
268
+ return null;
269
+ }
270
+ return (
271
+ <ListItem
272
+ key={originalIndex}
273
+ button
274
+ onClick={() => handlePopupTabClick(originalIndex)}
275
+ className="popover-list-item"
276
+ >
277
+ <span className="popover-tab-name">
278
+ {tab.name}
279
+ </span>
280
+ <span className="popover-tab-count">
281
+ {tab.count || ''}
282
+ </span>
283
+ </ListItem>
284
+ );
285
+ })}
286
+ </List>
287
+ </Popover>
288
+ )}
289
+ </div>
79
290
  </ThemeProvider>
80
291
  );
81
292
  };
@@ -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>