@bydata/react-supertabs 1.2.5 → 1.2.6
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/SuperTabs.js +10 -3
- 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/SuperTabs.js
CHANGED
|
@@ -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 = [];
|
|
@@ -884,7 +891,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
884
891
|
className: 'child-tabs-wrapper tab-' + tab.id + (showSubTabs ? ' expanded' : '')
|
|
885
892
|
// (isActive ? ' active' : '')
|
|
886
893
|
}, /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
887
|
-
content: tab.title,
|
|
894
|
+
content: getTooltipContent(tab, tab.title),
|
|
888
895
|
delay: 500,
|
|
889
896
|
followCursor: true,
|
|
890
897
|
placement: "bottom",
|
|
@@ -1002,7 +1009,7 @@ var SuperTabs = function SuperTabs(_ref) {
|
|
|
1002
1009
|
isDragDisabled: isMobileScreen
|
|
1003
1010
|
}, function (provided, snapshot) {
|
|
1004
1011
|
return /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
1005
|
-
content: tab.title,
|
|
1012
|
+
content: getTooltipContent(tab, tab.title),
|
|
1006
1013
|
delay: 500,
|
|
1007
1014
|
followCursor: true,
|
|
1008
1015
|
placement: "bottom",
|
|
@@ -1186,7 +1193,7 @@ var SubTab = exports.SubTab = function SubTab(_ref0) {
|
|
|
1186
1193
|
index: subIndex
|
|
1187
1194
|
}, function (subprovided, snapshot) {
|
|
1188
1195
|
return /*#__PURE__*/_react["default"].createElement(_reactHoverText["default"], {
|
|
1189
|
-
content: title,
|
|
1196
|
+
content: getTooltipContent(subTab, title),
|
|
1190
1197
|
delay: 500,
|
|
1191
1198
|
followCursor: true,
|
|
1192
1199
|
show: showTooltip,
|
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
|
-
```
|