@rango-dev/widget-embedded 0.20.1-next.22 → 0.20.1-next.23

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.
Files changed (82) hide show
  1. package/dist/QueueManager.d.ts.map +1 -1
  2. package/dist/components/ConfirmWalletsModal/ConfirmWallets.styles.d.ts +3 -3
  3. package/dist/components/ConfirmWalletsModal/WalletList.d.ts.map +1 -1
  4. package/dist/components/Layout/Layout.d.ts.map +1 -1
  5. package/dist/components/Quote/Quote.styles.d.ts +2 -2
  6. package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts +1 -0
  7. package/dist/components/QuoteWarningsAndErrors/HighValueLossWarningModal.d.ts.map +1 -1
  8. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.d.ts.map +1 -1
  9. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts +1 -0
  10. package/dist/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.d.ts.map +1 -1
  11. package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts +1 -0
  12. package/dist/components/QuoteWarningsAndErrors/SlippageWariningModal.d.ts.map +1 -1
  13. package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts +1 -0
  14. package/dist/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.d.ts.map +1 -1
  15. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  16. package/dist/components/SwapDetailsModal/SwapDetailsModal.WalletState.d.ts.map +1 -1
  17. package/dist/components/SwapDetailsModal/SwapDetailsModal.d.ts.map +1 -1
  18. package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts +2 -0
  19. package/dist/components/SwapDetailsModal/SwapDetailsModal.types.d.ts.map +1 -1
  20. package/dist/components/common/ActivateTabAlert/ActivateTabAlert.d.ts +4 -0
  21. package/dist/components/common/ActivateTabAlert/ActivateTabAlert.d.ts.map +1 -0
  22. package/dist/components/common/ActivateTabAlert/ActivateTabAlert.types.d.ts +4 -0
  23. package/dist/components/common/ActivateTabAlert/ActivateTabAlert.types.d.ts.map +1 -0
  24. package/dist/components/common/ActivateTabAlert/index.d.ts +2 -0
  25. package/dist/components/common/ActivateTabAlert/index.d.ts.map +1 -0
  26. package/dist/components/common/ActivateTabModal/ActivateTabModal.d.ts +4 -0
  27. package/dist/components/common/ActivateTabModal/ActivateTabModal.d.ts.map +1 -0
  28. package/dist/components/common/ActivateTabModal/ActivateTabModal.types.d.ts +6 -0
  29. package/dist/components/common/ActivateTabModal/ActivateTabModal.types.d.ts.map +1 -0
  30. package/dist/components/common/ActivateTabModal/index.d.ts +2 -0
  31. package/dist/components/common/ActivateTabModal/index.d.ts.map +1 -0
  32. package/dist/containers/Wallets/Wallets.d.ts.map +1 -1
  33. package/dist/containers/Widget/Widget.d.ts.map +1 -1
  34. package/dist/containers/WidgetInfo/WidgetInfo.d.ts.map +1 -1
  35. package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts +2 -0
  36. package/dist/containers/WidgetInfo/WidgetInfo.types.d.ts.map +1 -1
  37. package/dist/index.js +2 -2
  38. package/dist/index.js.map +4 -4
  39. package/dist/libs/tabManager/index.d.ts +3 -0
  40. package/dist/libs/tabManager/index.d.ts.map +1 -0
  41. package/dist/libs/tabManager/tabManager.constants.d.ts +4 -0
  42. package/dist/libs/tabManager/tabManager.constants.d.ts.map +1 -0
  43. package/dist/libs/tabManager/tabManager.d.ts +63 -0
  44. package/dist/libs/tabManager/tabManager.d.ts.map +1 -0
  45. package/dist/libs/tabManager/tabManager.types.d.ts +29 -0
  46. package/dist/libs/tabManager/tabManager.types.d.ts.map +1 -0
  47. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  48. package/dist/pages/Home.d.ts.map +1 -1
  49. package/dist/pages/WalletsPage.d.ts.map +1 -1
  50. package/dist/store/ui.d.ts +24 -0
  51. package/dist/store/ui.d.ts.map +1 -0
  52. package/package.json +5 -5
  53. package/src/QueueManager.tsx +4 -1
  54. package/src/components/ConfirmWalletsModal/WalletList.tsx +3 -0
  55. package/src/components/Layout/Layout.tsx +36 -2
  56. package/src/components/QuoteWarningsAndErrors/HighValueLossWarningModal.tsx +3 -1
  57. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.tsx +3 -1
  58. package/src/components/QuoteWarningsAndErrors/QuoteWarningsAndErrors.types.ts +1 -0
  59. package/src/components/QuoteWarningsAndErrors/SlippageWariningModal.tsx +3 -1
  60. package/src/components/QuoteWarningsAndErrors/UnknownPriceWarningModal.tsx +3 -1
  61. package/src/components/SwapDetails/SwapDetails.tsx +3 -0
  62. package/src/components/SwapDetailsModal/SwapDetailsModal.WalletState.tsx +9 -1
  63. package/src/components/SwapDetailsModal/SwapDetailsModal.tsx +10 -2
  64. package/src/components/SwapDetailsModal/SwapDetailsModal.types.ts +2 -0
  65. package/src/components/common/ActivateTabAlert/ActivateTabAlert.tsx +26 -0
  66. package/src/components/common/ActivateTabAlert/ActivateTabAlert.types.ts +3 -0
  67. package/src/components/common/ActivateTabAlert/index.ts +1 -0
  68. package/src/components/common/ActivateTabModal/ActivateTabModal.tsx +31 -0
  69. package/src/components/common/ActivateTabModal/ActivateTabModal.types.ts +5 -0
  70. package/src/components/common/ActivateTabModal/index.ts +1 -0
  71. package/src/containers/Wallets/Wallets.tsx +3 -1
  72. package/src/containers/Widget/Widget.tsx +6 -1
  73. package/src/containers/WidgetInfo/WidgetInfo.tsx +5 -1
  74. package/src/containers/WidgetInfo/WidgetInfo.types.ts +2 -0
  75. package/src/libs/tabManager/index.ts +2 -0
  76. package/src/libs/tabManager/tabManager.constants.ts +3 -0
  77. package/src/libs/tabManager/tabManager.ts +222 -0
  78. package/src/libs/tabManager/tabManager.types.ts +28 -0
  79. package/src/pages/ConfirmSwapPage.tsx +4 -1
  80. package/src/pages/Home.tsx +4 -1
  81. package/src/pages/WalletsPage.tsx +3 -0
  82. package/src/store/ui.ts +49 -0
@@ -7,6 +7,7 @@ import { useLanguage } from '../../hooks/useLanguage';
7
7
  import { useAppStore } from '../../store/AppStore';
8
8
  import { useNotificationStore } from '../../store/notification';
9
9
  import { useQuoteStore } from '../../store/quote';
10
+ import { setCurrentTabAsActive, useUiStore } from '../../store/ui';
10
11
  import { useWalletsStore } from '../../store/wallets';
11
12
  import { calculateWalletUsdValue } from '../../utils/wallets';
12
13
 
@@ -18,6 +19,7 @@ export const WidgetInfoContext = createContext<
18
19
 
19
20
  export function WidgetInfo(props: React.PropsWithChildren) {
20
21
  const { manager } = useManager();
22
+ const isActiveTab = useUiStore.use.isActiveTab();
21
23
  const retrySwap = useQuoteStore.use.retry();
22
24
  const history = new WidgetHistory(manager, { retrySwap });
23
25
  const details = useWalletsStore.use.connectedWallets();
@@ -32,7 +34,9 @@ export function WidgetInfo(props: React.PropsWithChildren) {
32
34
  const notifications = useNotificationStore().getUnreadNotifications();
33
35
 
34
36
  // eslint-disable-next-line react/jsx-no-constructed-context-values
35
- const value = {
37
+ const value: WidgetInfoContextInterface = {
38
+ isActiveTab,
39
+ setCurrentTabAsActive,
36
40
  history,
37
41
  wallets: {
38
42
  isLoading,
@@ -6,6 +6,8 @@ import type { Notification } from '../../types/notification';
6
6
  import type { BlockchainMeta, SwapperMeta, Token } from 'rango-sdk';
7
7
 
8
8
  export interface WidgetInfoContextInterface {
9
+ isActiveTab: boolean;
10
+ setCurrentTabAsActive: () => void;
9
11
  history: WidgetHistory;
10
12
  wallets: {
11
13
  details: ConnectedWallet[];
@@ -0,0 +1,2 @@
1
+ export { TabManager } from './tabManager';
2
+ export type { TabManagerInterface } from './tabManager.types';
@@ -0,0 +1,3 @@
1
+ export const TIMEOUT = 300;
2
+ export const MAXIMUM_TAB_ID = 100_000;
3
+ export const CHANNEL_NAME = 'rango-widget';
@@ -0,0 +1,222 @@
1
+ import type {
2
+ Events,
3
+ ID,
4
+ Message,
5
+ TabManagerInterface,
6
+ } from './tabManager.types';
7
+
8
+ import { CHANNEL_NAME, MAXIMUM_TAB_ID, TIMEOUT } from './tabManager.constants';
9
+
10
+ export class TabManager implements TabManagerInterface {
11
+ private tabId: ID;
12
+ private state: 'not-initiated' | 'not-claimed' | 'claimed' = 'not-initiated';
13
+ private lastTryClaim: number | undefined;
14
+ private events: Events = {};
15
+ private channel: BroadcastChannel;
16
+
17
+ constructor(events: Events) {
18
+ this.channel = new BroadcastChannel(CHANNEL_NAME);
19
+ this.tabId = Math.trunc(Math.random() * MAXIMUM_TAB_ID);
20
+ this.events = events;
21
+ this.initEvents();
22
+ void this.tryClaim();
23
+ }
24
+
25
+ /**
26
+ * This is applicable when a user in an inactive tab seeks to activate that tab.
27
+ */
28
+ forceClaim = () => {
29
+ if (!this.isClaimed()) {
30
+ const message: Message = { name: 'force-claim', candidateId: this.tabId };
31
+ this.channel.postMessage(message);
32
+ setTimeout(() => {
33
+ if (!this.isClaimed()) {
34
+ this.claim();
35
+ }
36
+ }, TIMEOUT);
37
+ }
38
+ };
39
+
40
+ isClaimed = () => {
41
+ return this.state === 'claimed';
42
+ };
43
+
44
+ /**
45
+ * remove event listeners
46
+ */
47
+ destroy = () => {
48
+ this.channel.removeEventListener('message', this.handleMessageEvent);
49
+ document.removeEventListener(
50
+ 'visibilitychange',
51
+ this.handleVisibilityChange
52
+ );
53
+ document.removeEventListener('resume', this.handleResume);
54
+ };
55
+
56
+ /**
57
+ * Reacting to messages and window events to claim.
58
+ */
59
+ private initEvents() {
60
+ this.channel.addEventListener('message', this.handleMessageEvent);
61
+
62
+ document.addEventListener('visibilitychange', this.handleVisibilityChange);
63
+
64
+ /**
65
+ * The "resume" event is currently supported only in certain browsers.
66
+ * It is triggered when a previously frozen tab is unfrozen and resumes execution.
67
+ * To avoid having multiple active tabs,
68
+ * if the current tab is active after the "resume" event,
69
+ * we send a signal to other tabs to verify if any of them currently claim to be active.
70
+ * If this is the case, we deactivate the current tab.
71
+ * https://developer.chrome.com/docs/web-platform/page-lifecycle-api
72
+ */
73
+ document.addEventListener('resume', this.handleResume);
74
+ }
75
+
76
+ /**
77
+ * Runs after a `ping` message and checks if current tab is claimed the tabs,
78
+ * if yes, it responds with `pong`, If not, it doesn't do anything.
79
+ *
80
+ * Note 1: If we receive a `ping` message,
81
+ * it means a tab is trying to claim tabs directly, usually it's the active tab.
82
+ *
83
+ * Note 2: If multiple tabs are opening at once, all of them are broadcasting `ping`
84
+ * and eventually all of them will `claim` the queue after the TIMEOUT.
85
+ * For avoiding this, we will accepts the oldest broadcasted ping. (`isPingSentBefore`)
86
+ */
87
+ private claimedByCurrentTab(pingAt: number) {
88
+ const isPingSentBefore = this.lastTryClaim && this.lastTryClaim < pingAt;
89
+
90
+ if (this.isClaimed() || isPingSentBefore) {
91
+ const message: Message = {
92
+ name: 'pong',
93
+ };
94
+ this.channel.postMessage(message);
95
+ return;
96
+ }
97
+ }
98
+
99
+ private handleMessageEvent = (event: MessageEvent<Message>) => {
100
+ const name = event.data.name;
101
+
102
+ switch (name) {
103
+ case 'ping':
104
+ this.claimedByCurrentTab(event.data.pingAt);
105
+ break;
106
+
107
+ case 'pong':
108
+ this.alreadyClaimedByAnotherTab();
109
+ break;
110
+
111
+ case 'force-claim':
112
+ this.forceRelease(event.data.candidateId);
113
+ break;
114
+
115
+ case 'force-release':
116
+ if (this.tabId === event.data.candidateId) {
117
+ this.claim();
118
+ }
119
+ break;
120
+
121
+ default:
122
+ throw new Error(`${name} is not supported.`);
123
+ }
124
+ };
125
+
126
+ private handleVisibilityChange = async () => {
127
+ if (document.visibilityState === 'visible') {
128
+ await this.tryClaim();
129
+ }
130
+ };
131
+
132
+ private handleResume = async () => {
133
+ if (this.isClaimed()) {
134
+ await this.tryClaim();
135
+ if (!this.isClaimed()) {
136
+ this.events.onRelease?.();
137
+ }
138
+ }
139
+ };
140
+ /**
141
+ * Runs after receiving `pong` message, which means one of tabs already claimed the tabs.
142
+ */
143
+ private alreadyClaimedByAnotherTab() {
144
+ this.resetLastCheck();
145
+ }
146
+
147
+ /**
148
+ * Try to send a `ping` message to know if the tabs `claimed` or not.
149
+ * On constructing instance, or whenever page is active we will try.
150
+ */
151
+ private async tryClaim() {
152
+ /**
153
+ * Try to ask from possible other running tabs.
154
+ */
155
+ this.setLastCheck();
156
+ return new Promise<void>((resolve) => {
157
+ setTimeout(() => {
158
+ this.check();
159
+ resolve();
160
+ }, TIMEOUT);
161
+ });
162
+ }
163
+
164
+ /**
165
+ * If `lastCheck` is exist, it means there is no other tabs which `claimed` the tabs.
166
+ * And we mark the current tab as `claimed`
167
+ */
168
+ private check() {
169
+ if (this.state === 'not-initiated') {
170
+ this.events.onInit?.();
171
+ }
172
+ /**
173
+ *it means we didn't get any response from other tabs, this tab can claim.
174
+ */
175
+ if (this.lastTryClaim) {
176
+ this.claim();
177
+ this.resetLastCheck();
178
+ } else {
179
+ this.state = 'not-claimed';
180
+ }
181
+ }
182
+
183
+ private claim() {
184
+ this.state = 'claimed';
185
+ this.events.onClaim?.();
186
+ }
187
+
188
+ /**
189
+ * Setting current time as `lastCheck` and broadcast a `ping` message event.
190
+ */
191
+ private setLastCheck() {
192
+ this.lastTryClaim = Date.now();
193
+ const message: Message = {
194
+ name: 'ping',
195
+ pingAt: this.lastTryClaim,
196
+ };
197
+ this.channel.postMessage(message);
198
+ }
199
+
200
+ private resetLastCheck() {
201
+ this.lastTryClaim = undefined;
202
+ }
203
+
204
+ /**
205
+ * Upon receipt of a "force-claim" message,
206
+ * the presently active tab is expected to deactivate itself and initiate any attached callback associated with this event.
207
+ */
208
+ private forceRelease(nextActiveTab: ID) {
209
+ if (this.isClaimed()) {
210
+ this.state = 'not-claimed';
211
+
212
+ this.events.onRelease?.();
213
+
214
+ const message: Message = {
215
+ name: 'force-release',
216
+ candidateId: nextActiveTab,
217
+ };
218
+
219
+ this.channel.postMessage(message);
220
+ }
221
+ }
222
+ }
@@ -0,0 +1,28 @@
1
+ export type ID = number;
2
+
3
+ type PingMessage = { name: 'ping'; pingAt: number };
4
+ type PongMessage = { name: 'pong' };
5
+ type ForceClaimMessage = {
6
+ name: 'force-claim';
7
+ candidateId: ID;
8
+ };
9
+ type ForceReleaseMessage = { name: 'force-release'; candidateId: ID };
10
+
11
+ export type Message =
12
+ | PingMessage
13
+ | PongMessage
14
+ | ForceClaimMessage
15
+ | ForceReleaseMessage;
16
+
17
+ export type Events = {
18
+ // Initially attempt to verify if the tab can be activated.
19
+ onInit?: () => void;
20
+ onClaim?: () => void;
21
+ onRelease?: () => void;
22
+ };
23
+
24
+ export interface TabManagerInterface {
25
+ forceClaim: () => void;
26
+ isClaimed: () => boolean;
27
+ destroy: () => void;
28
+ }
@@ -34,6 +34,7 @@ import { QuoteInfo } from '../containers/QuoteInfo';
34
34
  import { useConfirmSwap } from '../hooks/useConfirmSwap';
35
35
  import { useAppStore } from '../store/AppStore';
36
36
  import { useQuoteStore } from '../store/quote';
37
+ import { useUiStore } from '../store/ui';
37
38
  import { useWalletsStore } from '../store/wallets';
38
39
  import { QuoteWarningType } from '../types';
39
40
  import { getContainer } from '../utils/common';
@@ -86,6 +87,7 @@ export function ConfirmSwapPage() {
86
87
  const { connectedWallets } = useWalletsStore();
87
88
  const showWalletsOnInit = !quoteWalletsConfirmed;
88
89
  const [showWallets, setShowWallets] = useState(false);
90
+ const { isActiveTab } = useUiStore();
89
91
  const disabledLiquiditySources = useAppStore().disabledLiquiditySources;
90
92
  const prevDisabledLiquiditySources = useRef(disabledLiquiditySources);
91
93
  const { manager } = useManager();
@@ -282,6 +284,7 @@ export function ConfirmSwapPage() {
282
284
  loading={fetchingConfirmationQuote}
283
285
  refetchQuote={onRefresh}
284
286
  showWarningModal={showQuoteWarningModal}
287
+ confirmationDisabled={!isActiveTab}
285
288
  onOpenWarningModal={() => setShowQuoteWarningModal(true)}
286
289
  onCloseWarningModal={() => setShowQuoteWarningModal(false)}
287
290
  onConfirmWarningModal={async () => {
@@ -324,7 +327,7 @@ export function ConfirmSwapPage() {
324
327
  size="large"
325
328
  fullWidth
326
329
  loading={fetchingConfirmationQuote}
327
- disabled={!!confirmSwapResult.error}
330
+ disabled={!!confirmSwapResult.error || !isActiveTab}
328
331
  onClick={onStartConfirmSwap}>
329
332
  {i18n.t('Start Swap')}
330
333
  </Button>
@@ -21,6 +21,7 @@ import { QuoteInfo } from '../containers/QuoteInfo';
21
21
  import { useSwapInput } from '../hooks/useSwapInput';
22
22
  import { useAppStore } from '../store/AppStore';
23
23
  import { useQuoteStore } from '../store/quote';
24
+ import { useUiStore } from '../store/ui';
24
25
  import { useWalletsStore } from '../store/wallets';
25
26
  import { getContainer } from '../utils/common';
26
27
  import { formatTooltipNumbers, numberToString } from '../utils/numbers';
@@ -64,6 +65,7 @@ export function Home() {
64
65
  const fetchMetaStatus = useAppStore().fetchStatus;
65
66
 
66
67
  const { connectedWallets, getBalanceFor } = useWalletsStore();
68
+ const { isActiveTab } = useUiStore();
67
69
  const [showQuoteWarningModal, setShowQuoteWarningModal] = useState(false);
68
70
  const fetchingBalance =
69
71
  !!fromBlockchain &&
@@ -128,7 +130,7 @@ export function Home() {
128
130
  <Button
129
131
  type="primary"
130
132
  size="large"
131
- disabled={swapButtonState.disabled}
133
+ disabled={swapButtonState.disabled || !isActiveTab}
132
134
  prefix={
133
135
  swapButtonState.action === 'confirm-warning' && <WarningIcon />
134
136
  }
@@ -271,6 +273,7 @@ export function Home() {
271
273
  loading={fetchingQuote}
272
274
  refetchQuote={fetchQuote}
273
275
  showWarningModal={showQuoteWarningModal}
276
+ confirmationDisabled={!isActiveTab}
274
277
  onOpenWarningModal={() => setShowQuoteWarningModal(true)}
275
278
  onCloseWarningModal={() => setShowQuoteWarningModal(false)}
276
279
  onConfirmWarningModal={() => {
@@ -8,6 +8,7 @@ import { Layout, PageContainer } from '../components/Layout';
8
8
  import { WalletModal } from '../components/WalletModal';
9
9
  import { useWalletList } from '../hooks/useWalletList';
10
10
  import { useAppStore } from '../store/AppStore';
11
+ import { useUiStore } from '../store/ui';
11
12
  import { getContainer } from '../utils/common';
12
13
 
13
14
  const ListContainer = styled('div', {
@@ -32,6 +33,7 @@ export function WalletsPage() {
32
33
  const [openModal, setOpenModal] = useState(false);
33
34
  const [selectedWalletType, setSelectedWalletType] = useState<WalletType>('');
34
35
  let modalTimerId: ReturnType<typeof setTimeout> | null = null;
36
+ const isActiveTab = useUiStore.use.isActiveTab();
35
37
 
36
38
  const { list, handleClick, error } = useWalletList({
37
39
  config,
@@ -79,6 +81,7 @@ export function WalletsPage() {
79
81
  void handleClick(type);
80
82
  }}
81
83
  isLoading={fetchMetaStatus === 'loading'}
84
+ disabled={!isActiveTab}
82
85
  />
83
86
  );
84
87
  })}
@@ -0,0 +1,49 @@
1
+ import type { TabManagerInterface } from '../libs/tabManager';
2
+
3
+ import { create } from 'zustand';
4
+
5
+ import { TabManager } from '../libs/tabManager';
6
+
7
+ import createSelectors from './selectors';
8
+
9
+ interface UiState {
10
+ isActiveTab: boolean;
11
+ tabManagerInitiated: boolean;
12
+ showActivateTabModal: boolean;
13
+ activateCurrentTab: (
14
+ setCurrentTabAsActive: () => void,
15
+ hasRunningSwaps: boolean
16
+ ) => void;
17
+ setShowActivateTabModal: (flag: boolean) => void;
18
+ }
19
+
20
+ export const useUiStore = createSelectors(
21
+ create<UiState>()((set, get) => ({
22
+ isActiveTab: false,
23
+ tabManagerInitiated: false,
24
+ showActivateTabModal: false,
25
+ activateCurrentTab: (setCurrentTabAsActive, hasRunningSwaps) => {
26
+ const { showActivateTabModal } = get();
27
+
28
+ if (!showActivateTabModal && hasRunningSwaps) {
29
+ set({ showActivateTabModal: true });
30
+ } else if (showActivateTabModal || !hasRunningSwaps) {
31
+ setCurrentTabAsActive();
32
+ }
33
+ },
34
+ setShowActivateTabModal: (flag) => {
35
+ set({ showActivateTabModal: flag });
36
+ },
37
+ }))
38
+ );
39
+
40
+ const tabManager: TabManagerInterface = new TabManager({
41
+ onInit: () => useUiStore.setState({ tabManagerInitiated: true }),
42
+ onClaim: () =>
43
+ useUiStore.setState({ isActiveTab: true, showActivateTabModal: false }),
44
+ onRelease: () => useUiStore.setState({ isActiveTab: false }),
45
+ });
46
+
47
+ export const setCurrentTabAsActive = tabManager.forceClaim;
48
+
49
+ export const destroyTabManager = tabManager.destroy;