@bydata/react-supertabs 1.2.5 → 1.2.7
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/Readme.md +322 -0
- package/dist/Constants.js +4 -2
- package/dist/Readme.md +2 -0
- package/dist/SuperLink.js +2 -2
- package/dist/SuperTabs.js +31 -25
- package/dist/SuperTabs.scss +1 -1
- package/dist/TabContext.js +27 -15
- package/dist/TabList.js +2 -2
- package/dist/Utils.js +6 -1
- package/dist/images/icon-stack.svg +6 -0
- package/package.json +1 -1
- package/README.md +0 -262
package/Readme.md
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# SuperTabs
|
|
2
|
+
|
|
3
|
+
`SuperTabs` is a production-ready React navigation library for managing parent tabs and nested sub-tabs in complex applications.
|
|
4
|
+
|
|
5
|
+
It provides a robust tab lifecycle with route integration, privilege-aware module access, and extensible UI controls for module-level workflows.
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- Parent tab and sub-tab navigation with URL synchronization
|
|
10
|
+
- Drag-and-drop tab reordering
|
|
11
|
+
- Configurable module actions (`showAddButton` and `customAddButtons`)
|
|
12
|
+
- Pluggable handlers for open, close, reorder, and fetch operations
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1) Setup
|
|
17
|
+
|
|
18
|
+
Wrap your app with `TabProvider`.
|
|
19
|
+
|
|
20
|
+
```jsx
|
|
21
|
+
import { TabProvider } from "components/SuperTabs/TabContext";
|
|
22
|
+
import { alertService } from "super-notifier";
|
|
23
|
+
|
|
24
|
+
<TabProvider
|
|
25
|
+
SITE_PREFIX={SITE_PREFIX}
|
|
26
|
+
SITE_PAGES={SITE_PAGES}
|
|
27
|
+
homeUrl="/app"
|
|
28
|
+
getUserDetails={getUser}
|
|
29
|
+
hasPrivilege={(privilege) => checkPrivilege(getUser().privileges, privilege)}
|
|
30
|
+
getTabs={getTabs}
|
|
31
|
+
handleOpenTab={handleOpenTab}
|
|
32
|
+
handleCloseTab={handleCloseTab}
|
|
33
|
+
handleReorderTabs={handleReorderTabs}
|
|
34
|
+
isDefaultExpanded={true}
|
|
35
|
+
alertService={alertService}
|
|
36
|
+
>
|
|
37
|
+
<Main />
|
|
38
|
+
</TabProvider>;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Render tabs in header:
|
|
42
|
+
|
|
43
|
+
```jsx
|
|
44
|
+
import SuperTabs from "components/SuperTabs/SuperTabs";
|
|
45
|
+
|
|
46
|
+
<header>
|
|
47
|
+
<SuperTabs />
|
|
48
|
+
</header>;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 2) `TabProvider` props
|
|
54
|
+
|
|
55
|
+
### Required
|
|
56
|
+
|
|
57
|
+
- `SITE_PREFIX: string`
|
|
58
|
+
- `SITE_PAGES: Array<SitePage>`
|
|
59
|
+
|
|
60
|
+
`SitePage` is typically:
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
{
|
|
64
|
+
id: 2,
|
|
65
|
+
title: "Recruiter",
|
|
66
|
+
url: "/app/recruiter/f-home",
|
|
67
|
+
privilege: "RECRUITER",
|
|
68
|
+
containsSubTabs: true,
|
|
69
|
+
showAddButton: true, // boolean or privilege array
|
|
70
|
+
customAddButtons: [
|
|
71
|
+
{ id: 1, name: "Data Grid", privilege: "RECRUITER" },
|
|
72
|
+
{ id: 2, name: "Trend Master", privilege: "RECRUITER" }
|
|
73
|
+
],
|
|
74
|
+
showInMobile: true, // optional
|
|
75
|
+
isExternal: false // optional
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Optional
|
|
80
|
+
|
|
81
|
+
- `homeUrl` (default: `/`)
|
|
82
|
+
- `entityIdentifierKey` (default: `organization_id`)
|
|
83
|
+
- `persistTabsAfterLogin` (default: `false`)
|
|
84
|
+
- `preventHomeRedirect` (default: `false`)
|
|
85
|
+
- When `true`, clicking home opens module menu instead of redirecting.
|
|
86
|
+
- `retainTabsAfterEntityChange` (default: `false`)
|
|
87
|
+
- `shouldRedirectToSubTab` (default: `true`)
|
|
88
|
+
- `isMobileView` (default: `false`)
|
|
89
|
+
- `isDefaultExpanded` (default: `false`)
|
|
90
|
+
- `getUserDetails` (function)
|
|
91
|
+
- `hasPrivilege` (function)
|
|
92
|
+
- `getTabs` (async function)
|
|
93
|
+
- `handleOpenTab` (async function)
|
|
94
|
+
- `handleCloseTab` (async function)
|
|
95
|
+
- `handleReorderTabs` (async function)
|
|
96
|
+
- `alertService` object with optional methods: `success`, `warning`, `error`, `info`, `alert`
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3) API callback contracts
|
|
101
|
+
|
|
102
|
+
### `getTabs({ payload, controller })`
|
|
103
|
+
|
|
104
|
+
Expected shape:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
{
|
|
108
|
+
status: 1,
|
|
109
|
+
tabs: [], // flat backend tabs with tab_info
|
|
110
|
+
current_tab: {} | null, // current tab from backend
|
|
111
|
+
hasNoTabs: false // true when backend has no open tabs
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `handleOpenTab(payload[, controller])`
|
|
116
|
+
|
|
117
|
+
Expected shape:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
{
|
|
121
|
+
status: 1,
|
|
122
|
+
tabId: 123,
|
|
123
|
+
children: [] // optional child tabs
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `handleCloseTab(tabId)`
|
|
128
|
+
|
|
129
|
+
Expected shape:
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
{
|
|
133
|
+
status: 1,
|
|
134
|
+
current_tab_id: 456 // optional
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### `handleReorderTabs(payload)`
|
|
139
|
+
|
|
140
|
+
Expected shape:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
{
|
|
144
|
+
status: 1;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 4) Opening tabs
|
|
151
|
+
|
|
152
|
+
### Option 1: `SuperLink`
|
|
153
|
+
|
|
154
|
+
```jsx
|
|
155
|
+
import SuperLink from "components/SuperTabs/SuperLink";
|
|
156
|
+
|
|
157
|
+
<SuperLink tab={page} isSubTab={false}>
|
|
158
|
+
{page.title}
|
|
159
|
+
</SuperLink>;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Open external links:
|
|
163
|
+
|
|
164
|
+
```jsx
|
|
165
|
+
<SuperLink tab={{ ...page, isExternal: true }} isSubTab={false} isExternal>
|
|
166
|
+
{page.title}
|
|
167
|
+
</SuperLink>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Option 2: `openSuperTabOnRowClick`
|
|
171
|
+
|
|
172
|
+
```jsx
|
|
173
|
+
import { useTabContext } from "components/SuperTabs/TabContext";
|
|
174
|
+
|
|
175
|
+
const { openSuperTabOnRowClick } = useTabContext();
|
|
176
|
+
|
|
177
|
+
function handleRowClick(row) {
|
|
178
|
+
openSuperTabOnRowClick({
|
|
179
|
+
tab: {
|
|
180
|
+
id: row.id,
|
|
181
|
+
name: row.name,
|
|
182
|
+
url: `/app/recruiter/f-${row.id}`,
|
|
183
|
+
},
|
|
184
|
+
isSubTab: true, // defaults to true
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 5) Tab object notes
|
|
192
|
+
|
|
193
|
+
Common fields:
|
|
194
|
+
|
|
195
|
+
- `id`
|
|
196
|
+
- `url`
|
|
197
|
+
- one of `name` / `title`
|
|
198
|
+
|
|
199
|
+
Optional:
|
|
200
|
+
|
|
201
|
+
- `showAvatar`, `firstName`, `lastName`, `imgSrc` or `img_url`
|
|
202
|
+
- `tooltip` for hover text; falls back to tab title/name when empty
|
|
203
|
+
- `isExternal`
|
|
204
|
+
- any extra metadata your module uses
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
{
|
|
208
|
+
id: 100,
|
|
209
|
+
url: "/app/profile/100",
|
|
210
|
+
tooltip: "Profile: John Doe",
|
|
211
|
+
firstName: "John",
|
|
212
|
+
lastName: "Doe",
|
|
213
|
+
showAvatar: true,
|
|
214
|
+
imgSrc: "https://cdn.example.com/u100.png"
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 6) Add button callbacks
|
|
221
|
+
|
|
222
|
+
Bind module add callbacks using emitter:
|
|
223
|
+
|
|
224
|
+
```jsx
|
|
225
|
+
import { useCallback, useEffect } from "react";
|
|
226
|
+
import { emitter } from "components/SuperTabs/SuperTabs";
|
|
227
|
+
import { useTabContext } from "components/SuperTabs/TabContext";
|
|
228
|
+
|
|
229
|
+
const { openSuperTabOnRowClick } = useTabContext();
|
|
230
|
+
|
|
231
|
+
const handleTabAddBtn = useCallback(
|
|
232
|
+
(customButtonData) => {
|
|
233
|
+
// customButtonData is passed when using customAddButtons
|
|
234
|
+
openSuperTabOnRowClick({
|
|
235
|
+
tab: {
|
|
236
|
+
id: 123,
|
|
237
|
+
name: "New Funnel",
|
|
238
|
+
url: "/app/recruiter/f-123",
|
|
239
|
+
},
|
|
240
|
+
isSubTab: true,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
[openSuperTabOnRowClick],
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
useEffect(() => {
|
|
247
|
+
const unsub = emitter.emit("bindCallback", {
|
|
248
|
+
id: 2, // same parent module id from SITE_PAGES
|
|
249
|
+
callback: handleTabAddBtn,
|
|
250
|
+
});
|
|
251
|
+
return unsub;
|
|
252
|
+
}, [handleTabAddBtn]);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 7) Close cleanup event
|
|
258
|
+
|
|
259
|
+
```jsx
|
|
260
|
+
import { useEffect } from "react";
|
|
261
|
+
import { emitter } from "components/SuperTabs/SuperTabs";
|
|
262
|
+
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
const unsub = emitter.subscribe(
|
|
265
|
+
"superTabClose",
|
|
266
|
+
({ appId, isSubTab, tab }) => {
|
|
267
|
+
if (appId === 2 && isSubTab) {
|
|
268
|
+
// cleanup here
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
return unsub;
|
|
273
|
+
}, []);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 8) Not Available page
|
|
279
|
+
|
|
280
|
+
```jsx
|
|
281
|
+
import NotAvailable from "components/SuperTabs/NotAvailable";
|
|
282
|
+
|
|
283
|
+
<NotAvailable subTabName="Profile" />;
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 9) Keep-alive (optional)
|
|
289
|
+
|
|
290
|
+
Use shared keep-alive utility:
|
|
291
|
+
|
|
292
|
+
```jsx
|
|
293
|
+
import { withKeepAlive } from "components/KeepAlive";
|
|
294
|
+
|
|
295
|
+
const Component = () => <div>Component</div>;
|
|
296
|
+
export default withKeepAlive(Component, 2); // module id
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Cleanup keep-alive cache on parent tab close:
|
|
300
|
+
|
|
301
|
+
```jsx
|
|
302
|
+
import { useEffect } from "react";
|
|
303
|
+
import { useAliveScope } from "components/KeepAlive";
|
|
304
|
+
import { emitter } from "components/SuperTabs/SuperTabs";
|
|
305
|
+
|
|
306
|
+
const { drop } = useAliveScope();
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
const unsub = emitter.subscribe("superTabClose", ({ appId, isSubTab }) => {
|
|
310
|
+
if (appId && !isSubTab) {
|
|
311
|
+
drop(appId);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return unsub;
|
|
315
|
+
}, [drop]);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 10) Styling note
|
|
321
|
+
|
|
322
|
+
Home tab logo can be styled with `.brand-logo`.
|
package/dist/Constants.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.transitionDurationExtended = exports.transitionDuration = exports.fontStyle = exports.ToolbarButtonWidth = exports.SubTabWrapperPadding = exports.SubTabPadding = exports.SubTabGap = exports.StackButtonWidth = exports.MarginLeft = exports.MainTabGap = exports.HomeTabWidth = exports.CloseButtonWidth = exports.AvatarSize = void 0;
|
|
6
|
+
exports.transitionDurationExtended = exports.transitionDuration = exports.fontStyle = exports.ToolbarButtonWidth = exports.SubTabWrapperPadding = exports.SubTabPadding = exports.SubTabGap = exports.StackButtonWidth = exports.MarginLeft = exports.MainTabGap = exports.HomeTabWidth = exports.DEFAULT_HOME_URL = exports.CloseButtonWidth = exports.AvatarSize = void 0;
|
|
7
7
|
var transitionDuration = exports.transitionDuration = 300;
|
|
8
8
|
var transitionDurationExtended = exports.transitionDurationExtended = 800;
|
|
9
9
|
var HomeTabWidth = exports.HomeTabWidth = 36;
|
|
@@ -17,4 +17,6 @@ var AvatarSize = exports.AvatarSize = 20 + SubTabGap;
|
|
|
17
17
|
var ToolbarButtonWidth = exports.ToolbarButtonWidth = 24;
|
|
18
18
|
var CloseButtonWidth = exports.CloseButtonWidth = 20; // 24-4px is for the right padding adjustment
|
|
19
19
|
|
|
20
|
-
var fontStyle = exports.fontStyle = '600 12px "Open Sans", "Poppins", sans-serif'; // "same as supertabs.scss global font style"
|
|
20
|
+
var fontStyle = exports.fontStyle = '600 12px "Open Sans", "Poppins", sans-serif'; // "same as supertabs.scss global font style"
|
|
21
|
+
|
|
22
|
+
var DEFAULT_HOME_URL = exports.DEFAULT_HOME_URL = "/";
|
package/dist/Readme.md
CHANGED
|
@@ -199,6 +199,7 @@ Common fields:
|
|
|
199
199
|
Optional:
|
|
200
200
|
|
|
201
201
|
- `showAvatar`, `firstName`, `lastName`, `imgSrc` or `img_url`
|
|
202
|
+
- `tooltip` for hover text; falls back to tab title/name when empty
|
|
202
203
|
- `isExternal`
|
|
203
204
|
- any extra metadata your module uses
|
|
204
205
|
|
|
@@ -206,6 +207,7 @@ Optional:
|
|
|
206
207
|
{
|
|
207
208
|
id: 100,
|
|
208
209
|
url: "/app/profile/100",
|
|
210
|
+
tooltip: "Profile: John Doe",
|
|
209
211
|
firstName: "John",
|
|
210
212
|
lastName: "Doe",
|
|
211
213
|
showAvatar: true,
|
package/dist/SuperLink.js
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports["default"] = void 0;
|
|
7
7
|
var _react = _interopRequireDefault(require("react"));
|
|
8
|
-
var
|
|
8
|
+
var _reactRouter = require("react-router");
|
|
9
9
|
var _TabContext = require("./TabContext");
|
|
10
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
11
11
|
var SuperLink = function SuperLink(_ref) {
|
|
@@ -28,7 +28,7 @@ var SuperLink = function SuperLink(_ref) {
|
|
|
28
28
|
isSubTab: isSubTab
|
|
29
29
|
});
|
|
30
30
|
};
|
|
31
|
-
return /*#__PURE__*/_react["default"].createElement(
|
|
31
|
+
return /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, {
|
|
32
32
|
to: tab.url,
|
|
33
33
|
title: tab.title || '',
|
|
34
34
|
onClick: handleSuperLinkClick
|
package/dist/SuperTabs.js
CHANGED
|
@@ -5,13 +5,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.emitter = exports["default"] = exports.SubTab = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
-
var
|
|
8
|
+
var _reactRouter = require("react-router");
|
|
9
9
|
var _superDnd = require("super-dnd");
|
|
10
|
-
var _ClickOutsideListener = _interopRequireDefault(require("./ClickOutsideListener"));
|
|
11
|
-
var _reactHoverText = _interopRequireDefault(require("react-hover-text"));
|
|
12
10
|
var _superAvatar = _interopRequireDefault(require("super-avatar"));
|
|
13
|
-
var _SuperLink = _interopRequireDefault(require("./SuperLink"));
|
|
14
11
|
var _TabStack = _interopRequireDefault(require("./TabStack"));
|
|
12
|
+
var _ClickOutsideListener = _interopRequireDefault(require("./ClickOutsideListener"));
|
|
13
|
+
var _SuperLink = _interopRequireDefault(require("./SuperLink"));
|
|
14
|
+
var _reactHoverText = _interopRequireDefault(require("react-hover-text"));
|
|
15
15
|
var _TabContext = require("./TabContext");
|
|
16
16
|
var _eventEmitter = _interopRequireDefault(require("./eventEmitter"));
|
|
17
17
|
var _Utils = require("./Utils");
|
|
@@ -56,6 +56,13 @@ var tooltipStyles = {
|
|
|
56
56
|
backgroundColor: 'var(--tab-background-overlay, #272B32)',
|
|
57
57
|
color: 'var(--tab-text-normal, #BDC3CC)'
|
|
58
58
|
};
|
|
59
|
+
var getTooltipContent = function getTooltipContent(item, fallbackTitle) {
|
|
60
|
+
var customTooltip = item === null || item === void 0 ? void 0 : item.tooltip;
|
|
61
|
+
if (typeof customTooltip === 'string' && customTooltip.trim()) {
|
|
62
|
+
return customTooltip.trim();
|
|
63
|
+
}
|
|
64
|
+
return fallbackTitle;
|
|
65
|
+
};
|
|
59
66
|
var filterSubTabs = function filterSubTabs(subTabs) {
|
|
60
67
|
// const subTabsInList = [];
|
|
61
68
|
var subTabsInNavbar = [];
|
|
@@ -72,11 +79,10 @@ var filterSubTabs = function filterSubTabs(subTabs) {
|
|
|
72
79
|
// return { subTabsInList, subTabsInNavbar };
|
|
73
80
|
};
|
|
74
81
|
var getActiveParentTabName = function getActiveParentTabName(url, homeUrl) {
|
|
75
|
-
var
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return url.split('/')[2]; // e.g. /app/organization/1 => organization (has app prefix)
|
|
82
|
+
var urlSegments = url.split('/').filter(Boolean);
|
|
83
|
+
// if homeUrl is default, return the first segment (e.g. /organization/1 => organization, /recruiter/home => recruiter)
|
|
84
|
+
// if not default, return the second segment (e.g. /app/organization/1 => organization (has app prefix))
|
|
85
|
+
return homeUrl === _Constants.DEFAULT_HOME_URL ? urlSegments[0] : urlSegments[1];
|
|
80
86
|
};
|
|
81
87
|
|
|
82
88
|
// function calculateTransitionDuration(totalWidth, avgWidth = maxTabWidth) {
|
|
@@ -150,8 +156,8 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
150
156
|
}, _callee);
|
|
151
157
|
}))();
|
|
152
158
|
}, [updateMaxWidth]);
|
|
153
|
-
var
|
|
154
|
-
var location = (0,
|
|
159
|
+
var navigate = (0, _reactRouter.useNavigate)();
|
|
160
|
+
var location = (0, _reactRouter.useLocation)();
|
|
155
161
|
var _useState = (0, _react.useState)(function (isDefaultExpanded) {
|
|
156
162
|
if (isDefaultExpanded) updateMaxWidth();
|
|
157
163
|
return isDefaultExpanded;
|
|
@@ -705,8 +711,8 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
705
711
|
return /*#__PURE__*/_react["default"].createElement("div", {
|
|
706
712
|
className: "super-tabs-wrapper",
|
|
707
713
|
ref: superTabsWrapperElemRef
|
|
708
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
709
|
-
to:
|
|
714
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, {
|
|
715
|
+
to: homeUrl,
|
|
710
716
|
className: "home-tab",
|
|
711
717
|
ref: homeTabRef
|
|
712
718
|
// activeClassName="active"
|
|
@@ -734,7 +740,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
734
740
|
});
|
|
735
741
|
resetMaxWidth();
|
|
736
742
|
},
|
|
737
|
-
|
|
743
|
+
end: true
|
|
738
744
|
}, /*#__PURE__*/_react["default"].createElement("div", {
|
|
739
745
|
className: "brand-wrapper"
|
|
740
746
|
}, /*#__PURE__*/_react["default"].createElement("span", {
|
|
@@ -884,12 +890,12 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
884
890
|
className: 'child-tabs-wrapper tab-' + tab.id + (showSubTabs ? ' expanded' : '')
|
|
885
891
|
// (isActive ? ' active' : '')
|
|
886
892
|
}, /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
887
|
-
content: tab.title,
|
|
893
|
+
content: getTooltipContent(tab, tab.title),
|
|
888
894
|
delay: 500,
|
|
889
895
|
followCursor: true,
|
|
890
896
|
placement: "bottom",
|
|
891
897
|
stylingOptions: tooltipStyles
|
|
892
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
898
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, {
|
|
893
899
|
to: tab.url,
|
|
894
900
|
className: "tab" + " tab-" + tab.id + ((expandedTabID ? tab.width : maxWidth) && (0, _Utils.compareDecimals)(expandedTabID ? tab.width || width : maxWidth, width) === -1 ? ' fade-at-end' : '') + (!hasAccessToTab ? ' disabled-tab' : '') + (containsSubTabs ? ' has-child' : '') + (shrinkedTab ? ' shrinked-tab' : '')
|
|
895
901
|
// (showSubTabs ? ' expanded' : '')
|
|
@@ -922,7 +928,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
922
928
|
// return updated;
|
|
923
929
|
// });
|
|
924
930
|
}
|
|
925
|
-
|
|
931
|
+
navigate(lastOpenedTabUrl || tab.url);
|
|
926
932
|
// } else {
|
|
927
933
|
// setTimeout(() => {
|
|
928
934
|
// toggleSubTabs(tab);
|
|
@@ -935,7 +941,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
935
941
|
ignoreActiveTabUpdate: ignoreActiveTabUpdate
|
|
936
942
|
});
|
|
937
943
|
},
|
|
938
|
-
|
|
944
|
+
end: tab.fixed
|
|
939
945
|
}, /*#__PURE__*/_react["default"].createElement(TabContentWrapper, {
|
|
940
946
|
tab: tab,
|
|
941
947
|
index: index,
|
|
@@ -1002,12 +1008,12 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
1002
1008
|
isDragDisabled: isMobileScreen
|
|
1003
1009
|
}, function (provided, snapshot) {
|
|
1004
1010
|
return /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
1005
|
-
content: tab.title,
|
|
1011
|
+
content: getTooltipContent(tab, tab.title),
|
|
1006
1012
|
delay: 500,
|
|
1007
1013
|
followCursor: true,
|
|
1008
1014
|
placement: "bottom",
|
|
1009
1015
|
stylingOptions: tooltipStyles
|
|
1010
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
1016
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, _extends({}, provided.draggableProps, provided.dragHandleProps, {
|
|
1011
1017
|
ref: provided.innerRef,
|
|
1012
1018
|
to: url,
|
|
1013
1019
|
onClick: function onClick() {
|
|
@@ -1017,7 +1023,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
1017
1023
|
},
|
|
1018
1024
|
className: "tab parent-super-tab" + (snapshot.isDragging ? " dragging" : "") + (maxWidth && (0, _Utils.compareDecimals)(maxWidth, width) === -1 ? ' fade-at-end' : '') + (expandedTabID ? ' shrinked-tab' : '') + (!hasAccessToTab ? " disabled-tab" : ""),
|
|
1019
1025
|
style: getItemStyle(provided.draggableProps.style),
|
|
1020
|
-
|
|
1026
|
+
end: true
|
|
1021
1027
|
// exact={tab.exact}
|
|
1022
1028
|
// title={tab.title}
|
|
1023
1029
|
}), /*#__PURE__*/_react["default"].createElement(TabContentWrapper, {
|
|
@@ -1141,7 +1147,7 @@ var SubTab = exports.SubTab = function SubTab(_ref0) {
|
|
|
1141
1147
|
var _useTabContext3 = (0, _TabContext.useTabContext)(),
|
|
1142
1148
|
hiddenExternalToolbars = _useTabContext3.hiddenExternalToolbars,
|
|
1143
1149
|
tabModePreference = _useTabContext3.tabModePreference;
|
|
1144
|
-
var location = (0,
|
|
1150
|
+
var location = (0, _reactRouter.useLocation)();
|
|
1145
1151
|
var subTabUrl = (_subTab$url = subTab.url) !== null && _subTab$url !== void 0 ? _subTab$url : "/".concat(tabUrl, "/f-").concat(subTab.id);
|
|
1146
1152
|
var subTabUrlWithoutSearchParam = subTabUrl.split('?')[0];
|
|
1147
1153
|
var pathname = location.pathname;
|
|
@@ -1186,13 +1192,13 @@ var SubTab = exports.SubTab = function SubTab(_ref0) {
|
|
|
1186
1192
|
index: subIndex
|
|
1187
1193
|
}, function (subprovided, snapshot) {
|
|
1188
1194
|
return /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
1189
|
-
content: title,
|
|
1195
|
+
content: getTooltipContent(subTab, title),
|
|
1190
1196
|
delay: 500,
|
|
1191
1197
|
followCursor: true,
|
|
1192
1198
|
show: showTooltip,
|
|
1193
1199
|
placement: "bottom",
|
|
1194
1200
|
stylingOptions: tooltipStyles
|
|
1195
|
-
}, /*#__PURE__*/_react["default"].createElement(
|
|
1201
|
+
}, /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, _extends({}, subprovided.draggableProps, subprovided.dragHandleProps, {
|
|
1196
1202
|
ref: subprovided.innerRef,
|
|
1197
1203
|
to: subTabUrl,
|
|
1198
1204
|
id: "tab-".concat(tab.id, "-") + subTab.id.toString().replace('/', '-'),
|
|
@@ -1206,7 +1212,7 @@ var SubTab = exports.SubTab = function SubTab(_ref0) {
|
|
|
1206
1212
|
style: getItemStyle(showSubTabs || show, subprovided.draggableProps.style, width)
|
|
1207
1213
|
// title={subTab.name}
|
|
1208
1214
|
,
|
|
1209
|
-
|
|
1215
|
+
end: false,
|
|
1210
1216
|
onClick: function onClick() {
|
|
1211
1217
|
return handleTabClick({
|
|
1212
1218
|
tab: subTab,
|
package/dist/SuperTabs.scss
CHANGED
|
@@ -752,7 +752,7 @@ body[data-theme="light"] {
|
|
|
752
752
|
width: 5px;
|
|
753
753
|
height: 10px;
|
|
754
754
|
background-color: var(--tab-text-active);
|
|
755
|
-
mask: url(
|
|
755
|
+
mask: url(../../images/icon-chevron-right.svg) no-repeat center center;
|
|
756
756
|
mask-size: 5px;
|
|
757
757
|
transition: background-color ease-out var(--transition-duration),
|
|
758
758
|
var(--transition-duration) var(--transition-duration-extended);
|
package/dist/TabContext.js
CHANGED
|
@@ -9,7 +9,7 @@ exports.TabProvider = TabProvider;
|
|
|
9
9
|
exports.getUniqueIdentifier = void 0;
|
|
10
10
|
exports.useTabContext = useTabContext;
|
|
11
11
|
var _react = _interopRequireWildcard(require("react"));
|
|
12
|
-
var
|
|
12
|
+
var _reactRouter = require("react-router");
|
|
13
13
|
var _usePrevious = _interopRequireDefault(require("./usePrevious"));
|
|
14
14
|
var _Utils = require("./Utils");
|
|
15
15
|
var _Constants = require("./Constants");
|
|
@@ -154,7 +154,7 @@ function TabProvider(_ref9) {
|
|
|
154
154
|
SITE_PREFIX = _ref9.SITE_PREFIX,
|
|
155
155
|
SITE_PAGES = _ref9.SITE_PAGES,
|
|
156
156
|
_ref9$homeUrl = _ref9.homeUrl,
|
|
157
|
-
homeUrl = _ref9$homeUrl === void 0 ?
|
|
157
|
+
homeUrl = _ref9$homeUrl === void 0 ? _Constants.DEFAULT_HOME_URL : _ref9$homeUrl,
|
|
158
158
|
_ref9$entityIdentifie = _ref9.entityIdentifierKey,
|
|
159
159
|
entityIdentifierKey = _ref9$entityIdentifie === void 0 ? 'organization_id' : _ref9$entityIdentifie,
|
|
160
160
|
_ref9$persistTabsAfte = _ref9.persistTabsAfterLogin,
|
|
@@ -211,8 +211,8 @@ function TabProvider(_ref9) {
|
|
|
211
211
|
isDefaultExpanded = _ref9$isDefaultExpand === void 0 ? false : _ref9$isDefaultExpand,
|
|
212
212
|
_ref9$alertService = _ref9.alertService,
|
|
213
213
|
alertService = _ref9$alertService === void 0 ? {} : _ref9$alertService;
|
|
214
|
-
var
|
|
215
|
-
var location = (0,
|
|
214
|
+
var navigate = (0, _reactRouter.useNavigate)();
|
|
215
|
+
var location = (0, _reactRouter.useLocation)();
|
|
216
216
|
var homeTabIdRef = (0, _react.useRef)(null);
|
|
217
217
|
var superTabsWrapperElemRef = (0, _react.useRef)(null);
|
|
218
218
|
var _useState = (0, _react.useState)(false),
|
|
@@ -536,9 +536,11 @@ function TabProvider(_ref9) {
|
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
setTabModePreference(updatedTabModePreference);
|
|
539
|
-
|
|
539
|
+
navigate({
|
|
540
540
|
pathname: location.pathname,
|
|
541
541
|
search: "?".concat(searchParams.toString())
|
|
542
|
+
}, {
|
|
543
|
+
replace: true
|
|
542
544
|
});
|
|
543
545
|
};
|
|
544
546
|
var openSuperTabOnRowClick = function openSuperTabOnRowClick() {
|
|
@@ -553,7 +555,7 @@ function TabProvider(_ref9) {
|
|
|
553
555
|
var isTabOpen = !isSubTab && tabsRef.current.some(function (t) {
|
|
554
556
|
return t.url === tab.url;
|
|
555
557
|
});
|
|
556
|
-
|
|
558
|
+
navigate(tab.url);
|
|
557
559
|
// if (!isSubTab && tab.skipAPICall) return;
|
|
558
560
|
isSubTab ? openSubTab({
|
|
559
561
|
tab: tab
|
|
@@ -727,7 +729,7 @@ function TabProvider(_ref9) {
|
|
|
727
729
|
subTabs: _subTabs.sort(_Utils.sortByOrder)
|
|
728
730
|
}) : t;
|
|
729
731
|
});
|
|
730
|
-
var pathName =
|
|
732
|
+
var pathName = location.pathname;
|
|
731
733
|
var isSubTabActive = _subTabs.find(function (t) {
|
|
732
734
|
return t.url === pathName;
|
|
733
735
|
});
|
|
@@ -1189,7 +1191,9 @@ function TabProvider(_ref9) {
|
|
|
1189
1191
|
if (tabModePreference.includes(newActiveSubTab.tabId)) {
|
|
1190
1192
|
url += "?edit=true";
|
|
1191
1193
|
}
|
|
1192
|
-
|
|
1194
|
+
navigate(url, {
|
|
1195
|
+
replace: true
|
|
1196
|
+
});
|
|
1193
1197
|
} else {
|
|
1194
1198
|
updateActiveSubTab({});
|
|
1195
1199
|
lastOpenedUrl.current[currentEntityId + '_' + activeTabRef.current.id] = null;
|
|
@@ -1197,7 +1201,9 @@ function TabProvider(_ref9) {
|
|
|
1197
1201
|
if (tabModePreference.includes(activeTabRef.current.tabId)) {
|
|
1198
1202
|
_url += "?edit=true";
|
|
1199
1203
|
}
|
|
1200
|
-
|
|
1204
|
+
navigate(_url, {
|
|
1205
|
+
replace: true
|
|
1206
|
+
});
|
|
1201
1207
|
}
|
|
1202
1208
|
} else {
|
|
1203
1209
|
newTabs[parentTabIndex].subTabs = newTabs[parentTabIndex].subTabs.map(function (subTab) {
|
|
@@ -1230,11 +1236,15 @@ function TabProvider(_ref9) {
|
|
|
1230
1236
|
var newActiveTab = nextTab !== null && nextTab !== void 0 ? nextTab : newTabs[tabIndex - 1];
|
|
1231
1237
|
updateActiveTab(newActiveTab);
|
|
1232
1238
|
lastOpenedUrl.current[currentEntityId + '_' + activeTabRef.current.id] = newActiveTab;
|
|
1233
|
-
|
|
1239
|
+
navigate(newActiveTab.url, {
|
|
1240
|
+
replace: true
|
|
1241
|
+
});
|
|
1234
1242
|
} else {
|
|
1235
1243
|
lastOpenedUrl.current[currentEntityId + '_' + activeTabRef.current.id] = null;
|
|
1236
1244
|
updateActiveTab({});
|
|
1237
|
-
|
|
1245
|
+
navigate("/", {
|
|
1246
|
+
replace: true
|
|
1247
|
+
});
|
|
1238
1248
|
}
|
|
1239
1249
|
}
|
|
1240
1250
|
newTabs = newTabs.filter(function (t) {
|
|
@@ -1549,7 +1559,7 @@ function TabProvider(_ref9) {
|
|
|
1549
1559
|
_context10.n = 13;
|
|
1550
1560
|
break;
|
|
1551
1561
|
}
|
|
1552
|
-
pathName =
|
|
1562
|
+
pathName = location.pathname;
|
|
1553
1563
|
isHomeTab = pathName === homeUrl || pathName === '/';
|
|
1554
1564
|
_context10.n = 3;
|
|
1555
1565
|
return findDuplicateEntriesAndCloseTab(response.tabs);
|
|
@@ -1578,7 +1588,9 @@ function TabProvider(_ref9) {
|
|
|
1578
1588
|
// lastOpenedUrl.current[activeTab.id] = activeSubTab.url;
|
|
1579
1589
|
}
|
|
1580
1590
|
isHomeTab = false;
|
|
1581
|
-
|
|
1591
|
+
navigate(pathName, {
|
|
1592
|
+
replace: true
|
|
1593
|
+
});
|
|
1582
1594
|
}
|
|
1583
1595
|
isCurrentTabOpen = !isHomeTab && tabsOutput.find(function (tab) {
|
|
1584
1596
|
var _tab$tab_info$url;
|
|
@@ -1613,7 +1625,7 @@ function TabProvider(_ref9) {
|
|
|
1613
1625
|
_context10.n = 6;
|
|
1614
1626
|
break;
|
|
1615
1627
|
case 5:
|
|
1616
|
-
|
|
1628
|
+
navigate(homeUrl);
|
|
1617
1629
|
case 6:
|
|
1618
1630
|
_context10.n = 10;
|
|
1619
1631
|
break;
|
|
@@ -1806,7 +1818,7 @@ function TabProvider(_ref9) {
|
|
|
1806
1818
|
};
|
|
1807
1819
|
}());
|
|
1808
1820
|
if (activeTab.url) {
|
|
1809
|
-
|
|
1821
|
+
navigate(activeTab.url);
|
|
1810
1822
|
}
|
|
1811
1823
|
}
|
|
1812
1824
|
}
|
package/dist/TabList.js
CHANGED
|
@@ -8,7 +8,7 @@ exports["default"] = void 0;
|
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
9
|
var _reactDom = require("react-dom");
|
|
10
10
|
var _TabContext = require("./TabContext");
|
|
11
|
-
var
|
|
11
|
+
var _reactRouter = require("react-router");
|
|
12
12
|
var _ClickOutsideListener = _interopRequireDefault(require("./ClickOutsideListener"));
|
|
13
13
|
require("./TabList.scss");
|
|
14
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
@@ -188,7 +188,7 @@ var TabList = function TabList(_ref) {
|
|
|
188
188
|
className: "tab-list-tabs-wrapper"
|
|
189
189
|
}, filteredTabs.length > 0 ? filteredTabs.map(function (tab, index) {
|
|
190
190
|
var title = tab.title || tab.name || (tab !== null && tab !== void 0 && tab.firstName ? "".concat(tab.firstName, " ").concat(tab.lastName || '') : 'Untitled');
|
|
191
|
-
return /*#__PURE__*/_react["default"].createElement(
|
|
191
|
+
return /*#__PURE__*/_react["default"].createElement(_reactRouter.NavLink, {
|
|
192
192
|
className: "tab-list-open-tab ".concat(id === activeTab.id && tab.id === activeSubTab.id ? 'active' : ''),
|
|
193
193
|
key: tab.id || index,
|
|
194
194
|
onClick: function onClick(e) {
|
package/dist/Utils.js
CHANGED
|
@@ -13,7 +13,9 @@ exports.getTextWidth = getTextWidth;
|
|
|
13
13
|
exports.getUserDetailsFromToken = exports.getUniqueId = exports.getTitle = void 0;
|
|
14
14
|
exports.isChildPath = isChildPath;
|
|
15
15
|
exports.isDev = isDev;
|
|
16
|
-
exports.
|
|
16
|
+
exports.isEmpty = void 0;
|
|
17
|
+
exports.isStage = isStage;
|
|
18
|
+
exports.normalizeUrl = void 0;
|
|
17
19
|
exports.removeSpaces = removeSpaces;
|
|
18
20
|
exports.reorder = reorder;
|
|
19
21
|
exports.reorderSubTabs = reorderSubTabs;
|
|
@@ -163,6 +165,9 @@ function reorderSubTabs(array, sourceIndex, destinationIndex) {
|
|
|
163
165
|
function isDev() {
|
|
164
166
|
return process.env.REACT_APP_CUSTOM_NODE_ENV === 'development';
|
|
165
167
|
}
|
|
168
|
+
function isStage() {
|
|
169
|
+
return process.env.REACT_APP_CUSTOM_NODE_ENV === 'stage';
|
|
170
|
+
}
|
|
166
171
|
function removeSpaces(str) {
|
|
167
172
|
return str.replace(/\s/g, '');
|
|
168
173
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="36" height="30" viewBox="0 0 36 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M8 4.00098C8 2.89641 8.89543 2.00098 10 2.00098H32C33.1046 2.00098 34 2.89641 34 4.00098V26.001C34 27.1055 33.1046 28.001 32 28.001H10C8.89543 28.001 8 27.1055 8 26.001V4.00098Z" fill="#1D2024"/>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 0.000976562H32C34.2091 0.000976562 36 1.79184 36 4.00098V26.001C36 28.2101 34.2091 30.001 32 30.001H10C7.79086 30.001 6 28.2101 6 26.001V4.00098C6 1.79184 7.79086 0.000976562 10 0.000976562ZM10 2.00098C8.89543 2.00098 8 2.89641 8 4.00098V26.001C8 27.1055 8.89543 28.001 10 28.001H32C33.1046 28.001 34 27.1055 34 26.001V4.00098C34 2.89641 33.1046 2.00098 32 2.00098H10Z" fill="black"/>
|
|
4
|
+
<path d="M2 4.00098C2 2.89641 2.89543 2.00098 4 2.00098H26C27.1046 2.00098 28 2.89641 28 4.00098V26.001C28 27.1055 27.1046 28.001 26 28.001H4C2.89543 28.001 2 27.1055 2 26.001V4.00098Z" fill="#1D2024"/>
|
|
5
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 0.000976562H26C28.2091 0.000976562 30 1.79184 30 4.00098V26.001C30 28.2101 28.2091 30.001 26 30.001H4C1.79086 30.001 0 28.2101 0 26.001V4.00098C0 1.79184 1.79086 0.000976562 4 0.000976562ZM4 2.00098C2.89543 2.00098 2 2.89641 2 4.00098V26.001C2 27.1055 2.89543 28.001 4 28.001H26C27.1046 28.001 28 27.1055 28 26.001V4.00098C28 2.89641 27.1046 2.00098 26 2.00098H4Z" fill="black"/>
|
|
6
|
+
</svg>
|
package/package.json
CHANGED
package/README.md
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
# React SuperTabs
|
|
2
|
-
|
|
3
|
-
**SuperTabs** is a powerful and user-friendly tab management component. It enables seamless navigation by opening modules as tabs, with support for sub-tabs, smooth transitions. An experimental _keep-alive_ feature ensures components stay active across tab switches for enhanced usability.
|
|
4
|
-
|
|
5
|
-
### SuperTabs Features
|
|
6
|
-
------
|
|
7
|
-
- **Tab-based Navigation**: Open modules as tabs for an intuitive and efficient navigation experience.
|
|
8
|
-
- **Sub-Tabs Support**: Create nested sub-tabs within a main tab for hierarchical organization.
|
|
9
|
-
- **Smooth Transitions**: Enjoy a polished user experience with fluid tab-switching animations.
|
|
10
|
-
- **Keep-Alive (Experimental)**: Maintain the state of components across tab switches for seamless interaction (experimental feature).
|
|
11
|
-
|
|
12
|
-
### Installation
|
|
13
|
-
------
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install @bydata/react-supertabs
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### Usage
|
|
20
|
-
------
|
|
21
|
-
|
|
22
|
-
#### Basic
|
|
23
|
-
|
|
24
|
-
>**Import TabProvider and wrap it around the main wrapper**
|
|
25
|
-
|
|
26
|
-
- This is needed to access useTabContext.
|
|
27
|
-
- Make sure to pass `SITE_PREFIX` and `SITE_PAGES` (From Navigation.js)
|
|
28
|
-
- `homeUrl` is optional and defaults to "/"
|
|
29
|
-
- `persistTabsAfterLogin` is optional and defaults to "false"
|
|
30
|
-
- Used to preserve tab state upon login.
|
|
31
|
-
- `entityIdentifierKey` is optional and defaults to 'organization_id',
|
|
32
|
-
- Used to identify the organization / client id
|
|
33
|
-
- `preventHomeRedirect` is optional and defaults to false,
|
|
34
|
-
- This will open a menu on click of home button instead of redirecting
|
|
35
|
-
- `handleOpenTab` async function to open the tab in backend
|
|
36
|
-
- expects the following keys in return
|
|
37
|
-
- { status: 1, tabId, children: undefined }
|
|
38
|
-
- `handleCloseTab` async function to open the tab in backend
|
|
39
|
-
- expects the following keys in return
|
|
40
|
-
- { status: 1, current_tab_id: 123 }
|
|
41
|
-
- `handleReorderTabs` async function to open the tab in backend
|
|
42
|
-
- { status: 1 }
|
|
43
|
-
- `getTabs` async function to open the tab in backend async () => { },
|
|
44
|
-
- expects the following keys in return
|
|
45
|
-
- { status: 1, tabs: [], current_tab: {} || null, hasNoTabs }
|
|
46
|
-
- hasNoTabs = user for whom there are no tabs open
|
|
47
|
-
- `getUserDetails` function which return the user details from user token
|
|
48
|
-
- `hasPrivilege` function which checks if the user has the privilege passed in function param
|
|
49
|
-
- `alertService` An object containing different methods for displaying toast alerts.
|
|
50
|
-
- can call success, warning, error, info, alert methods.
|
|
51
|
-
- super-notifier - NPM package can be used here
|
|
52
|
-
- https://www.npmjs.com/package/super-notifier
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Eg.
|
|
56
|
-
const SITE_PREFIX = 'teamLink_'
|
|
57
|
-
const API_BASE_URL = 'https://api.teamlink.com/data_stream'
|
|
58
|
-
const SITE_PAGES = [{
|
|
59
|
-
title: "Organization",
|
|
60
|
-
url: "/app/organization",
|
|
61
|
-
privilege: "ORGANIZATION",
|
|
62
|
-
id: 1,
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
title: "Recruiter",
|
|
66
|
-
url: "/app/recruiter/f-home",
|
|
67
|
-
privilege: "RECRUITER",
|
|
68
|
-
showAddButton: true,
|
|
69
|
-
customAddButtons: [
|
|
70
|
-
{
|
|
71
|
-
name: "Data Grid",
|
|
72
|
-
id: 1,
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
name: "Trend Master",
|
|
76
|
-
id: 2,
|
|
77
|
-
}
|
|
78
|
-
],
|
|
79
|
-
containsSubTabs: true,
|
|
80
|
-
id: 2,
|
|
81
|
-
}]
|
|
82
|
-
|
|
83
|
-
// showAddButton - can be added if the module needs plus button.
|
|
84
|
-
// containsSubTabs - can be added if the tab includes sub tabs.
|
|
85
|
-
// customAddButtons - These buttons will be added in the sub tab list. Clicking on the button will trigger the binded callback with object as param.
|
|
86
|
-
|
|
87
|
-
import { TabProvider } from '@bydata/react-supertabs';
|
|
88
|
-
<TabProvider
|
|
89
|
-
SITE_PREFIX={SITE_PREFIX}
|
|
90
|
-
SITE_PAGES={SITE_PAGES}
|
|
91
|
-
homeUrl="/app"
|
|
92
|
-
getTabs={getTabs}
|
|
93
|
-
handleOpenTab={handleOpenTab}
|
|
94
|
-
handleCloseTab={handleCloseTab}
|
|
95
|
-
handleReorderTabs={handleReorderTabs}
|
|
96
|
-
alertService={alertService}
|
|
97
|
-
>
|
|
98
|
-
<Main />
|
|
99
|
-
</TabProvider>
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
>**Render the component within the App's header**
|
|
103
|
-
```
|
|
104
|
-
import { SuperTabs, useTabContext } from '@bydata/react-supertabs';
|
|
105
|
-
|
|
106
|
-
<header>
|
|
107
|
-
<SuperTabs />
|
|
108
|
-
</header>
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
>**Wrap the hyperlink as follows:**
|
|
112
|
-
|
|
113
|
-
Each tab should contain all the necessary information to be stored.
|
|
114
|
-
|
|
115
|
-
Mandatory Fields:
|
|
116
|
-
- `id`
|
|
117
|
-
- `name`
|
|
118
|
-
- `url`
|
|
119
|
-
|
|
120
|
-
For Avatar:
|
|
121
|
-
- `showAvatar` must be set to `true`
|
|
122
|
-
- The following fields must be provided:
|
|
123
|
-
- `firstName`
|
|
124
|
-
- `lastName`
|
|
125
|
-
- `imgSrc`
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
// Tab object Examples
|
|
129
|
-
|
|
130
|
-
{
|
|
131
|
-
id: 1,
|
|
132
|
-
name: 'title',
|
|
133
|
-
url: '/recruiter/f-1`
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
{
|
|
137
|
-
id: 100,
|
|
138
|
-
url: '/profile/100`
|
|
139
|
-
firstName: 'John',
|
|
140
|
-
lastName: 'Doe',
|
|
141
|
-
showAvatar: true,
|
|
142
|
-
imgSrc: img_url,
|
|
143
|
-
department,
|
|
144
|
-
designation,
|
|
145
|
-
department_id,
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
```
|
|
149
|
-
import { SuperLink } from '@bydata/react-supertabs';
|
|
150
|
-
<SuperLink tab={page} isSubTab={false}>
|
|
151
|
-
{page.title}
|
|
152
|
-
</SuperLink>
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
OR
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
import { useTabContext } from '@bydata/react-supertabs';
|
|
159
|
-
const { openSuperTabOnRowClick } = useTabContext();
|
|
160
|
-
|
|
161
|
-
function handleRowClick(e) {
|
|
162
|
-
const tab = { id: e.id, name: e.name, url: `/recruiter/f-${e.id}` };
|
|
163
|
-
// isSubTab defaults to true
|
|
164
|
-
openSuperTabOnRowClick({ tab, isSubTab });
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
>**Bind the callback for the plus button to each module during the initial render.**
|
|
169
|
-
|
|
170
|
-
If a module requires a plus button for adding a new tab, you can include the following:
|
|
171
|
-
```
|
|
172
|
-
import { emitter, useTabContext } from '@bydata/react-supertabs';
|
|
173
|
-
|
|
174
|
-
const { openSuperTabOnRowClick } = useTabContext();
|
|
175
|
-
|
|
176
|
-
const handleTabAddBtn = useCallback(() => {
|
|
177
|
-
openSuperTabOnRowClick({
|
|
178
|
-
tab: {
|
|
179
|
-
id: 123,
|
|
180
|
-
name: `New Funnel`,
|
|
181
|
-
url: `/recruiter/f-${123}`,
|
|
182
|
-
},
|
|
183
|
-
isSubTab: true,
|
|
184
|
-
});
|
|
185
|
-
}, [openSuperTabOnRowClick]);
|
|
186
|
-
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
const unsub = emitter.emit("bindCallback", {
|
|
189
|
-
id: 2, // Same id provided for this module in navigation.js
|
|
190
|
-
callback: handleTabAddBtn,
|
|
191
|
-
});
|
|
192
|
-
return unsub;
|
|
193
|
-
}, [handleTabAddBtn]);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
> Note: The logo of the home tab can be updated by targeting the `brand-logo` class.
|
|
197
|
-
|
|
198
|
-
-----
|
|
199
|
-
|
|
200
|
-
#### Advanced
|
|
201
|
-
|
|
202
|
-
>**Cleanup**
|
|
203
|
-
|
|
204
|
-
When a tab is closed, it may be necessary to clean up some data. The `superTabClose` event can be utilized for this purpose.
|
|
205
|
-
|
|
206
|
-
```
|
|
207
|
-
import { emitter } from '@bydata/react-supertabs';
|
|
208
|
-
|
|
209
|
-
useEffect(() => {
|
|
210
|
-
const unsub = emitter.subscribe('superTabClose', ({ appId, isSubTab, tab }) => {
|
|
211
|
-
// Same id provided for this module in navigation.js
|
|
212
|
-
if (appId === 2 && isSubTab) {
|
|
213
|
-
// handle clean up here
|
|
214
|
-
}
|
|
215
|
-
})
|
|
216
|
-
return unsub;
|
|
217
|
-
}, []);
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
>**Not Available page**
|
|
221
|
-
- If a profile is deleted, the tab will remain open. To address this, we can display a "Page Not Available" message.
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
import { NotAvailable } from '@bydata/react-supertabs';
|
|
225
|
-
|
|
226
|
-
<NotAvailable subTabName='Profile' />
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
>**Keep Alive (Experimental)**
|
|
230
|
-
|
|
231
|
-
```
|
|
232
|
-
import { withKeepAlive } from '@bydata/react-supertabs';
|
|
233
|
-
|
|
234
|
-
// Same id provided for this module in navigation.js
|
|
235
|
-
export default withKeepAlive(Component, Unique ID);
|
|
236
|
-
|
|
237
|
-
Eg.
|
|
238
|
-
const Component = () => {
|
|
239
|
-
return <div>Component</div>
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export default withKeepAlive(Component, 2);
|
|
243
|
-
```
|
|
244
|
-
Keep Alive Cleanup
|
|
245
|
-
```
|
|
246
|
-
// This can be incorporated into a component that is always rendered, such as the header.
|
|
247
|
-
|
|
248
|
-
import { useAliveScope, emitter } from '@bydata/react-supertabs';
|
|
249
|
-
|
|
250
|
-
const { drop } = useAliveScope();
|
|
251
|
-
|
|
252
|
-
useEffect(() => {
|
|
253
|
-
const unsub = emitter.subscribe('superTabClose', (e) => {
|
|
254
|
-
const { appId, isSubTab } = e;
|
|
255
|
-
if (appId && !isSubTab) {
|
|
256
|
-
// drop the cache of the tab
|
|
257
|
-
drop(appId);
|
|
258
|
-
}
|
|
259
|
-
})
|
|
260
|
-
return unsub;
|
|
261
|
-
}, []);
|
|
262
|
-
```
|