@zat-design/sisyphus-react 3.13.23 → 3.14.0-beta.1

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 (67) hide show
  1. package/es/ProLayout/components/Layout/Menu/FoldMenu/index.js +8 -4
  2. package/es/ProLayout/components/Layout/Menu/OpenMenu/index.js +39 -28
  3. package/es/ProLayout/components/TabsManager/components/TabContextMenu.d.ts +7 -0
  4. package/es/ProLayout/components/TabsManager/components/TabContextMenu.js +96 -0
  5. package/es/ProLayout/components/TabsManager/components/TabItem.d.ts +26 -0
  6. package/es/ProLayout/components/TabsManager/components/TabItem.js +61 -0
  7. package/es/ProLayout/components/TabsManager/components/TabsContext.d.ts +6 -0
  8. package/es/ProLayout/components/TabsManager/components/TabsContext.js +5 -0
  9. package/es/ProLayout/components/TabsManager/hooks/useActiveTab.d.ts +6 -0
  10. package/es/ProLayout/components/TabsManager/hooks/useActiveTab.js +14 -0
  11. package/es/ProLayout/components/TabsManager/hooks/useProLayoutTabs.d.ts +18 -0
  12. package/es/ProLayout/components/TabsManager/hooks/useProLayoutTabs.js +26 -0
  13. package/es/ProLayout/components/TabsManager/hooks/useTabsCache.d.ts +31 -0
  14. package/es/ProLayout/components/TabsManager/hooks/useTabsCache.js +93 -0
  15. package/es/ProLayout/components/TabsManager/hooks/useTabsState.d.ts +5 -0
  16. package/es/ProLayout/components/TabsManager/hooks/useTabsState.js +357 -0
  17. package/es/ProLayout/components/TabsManager/index.d.ts +8 -0
  18. package/es/ProLayout/components/TabsManager/index.js +171 -0
  19. package/es/ProLayout/components/TabsManager/propTypes.d.ts +74 -0
  20. package/es/ProLayout/components/TabsManager/propTypes.js +16 -0
  21. package/es/ProLayout/components/TabsManager/style/index.less +179 -0
  22. package/es/ProLayout/components/TabsManager/utils/index.d.ts +38 -0
  23. package/es/ProLayout/components/TabsManager/utils/index.js +106 -0
  24. package/es/ProLayout/index.d.ts +10 -4
  25. package/es/ProLayout/index.js +82 -9
  26. package/es/ProLayout/propTypes.d.ts +139 -1
  27. package/es/ProLayout/propTypes.js +37 -1
  28. package/es/ProUpload/components/DragRender.d.ts +1 -0
  29. package/es/ProUpload/components/DragRender.js +5 -1
  30. package/es/ProUpload/index.js +4 -2
  31. package/es/ProUpload/propsType.d.ts +5 -0
  32. package/es/index.d.ts +2 -1
  33. package/es/index.js +1 -1
  34. package/lib/ProLayout/components/Layout/Menu/FoldMenu/index.js +8 -4
  35. package/lib/ProLayout/components/Layout/Menu/OpenMenu/index.js +39 -28
  36. package/lib/ProLayout/components/TabsManager/components/TabContextMenu.d.ts +7 -0
  37. package/lib/ProLayout/components/TabsManager/components/TabContextMenu.js +103 -0
  38. package/lib/ProLayout/components/TabsManager/components/TabItem.d.ts +26 -0
  39. package/lib/ProLayout/components/TabsManager/components/TabItem.js +67 -0
  40. package/lib/ProLayout/components/TabsManager/components/TabsContext.d.ts +6 -0
  41. package/lib/ProLayout/components/TabsManager/components/TabsContext.js +11 -0
  42. package/lib/ProLayout/components/TabsManager/hooks/useActiveTab.d.ts +6 -0
  43. package/lib/ProLayout/components/TabsManager/hooks/useActiveTab.js +20 -0
  44. package/lib/ProLayout/components/TabsManager/hooks/useProLayoutTabs.d.ts +18 -0
  45. package/lib/ProLayout/components/TabsManager/hooks/useProLayoutTabs.js +31 -0
  46. package/lib/ProLayout/components/TabsManager/hooks/useTabsCache.d.ts +31 -0
  47. package/lib/ProLayout/components/TabsManager/hooks/useTabsCache.js +101 -0
  48. package/lib/ProLayout/components/TabsManager/hooks/useTabsState.d.ts +5 -0
  49. package/lib/ProLayout/components/TabsManager/hooks/useTabsState.js +364 -0
  50. package/lib/ProLayout/components/TabsManager/index.d.ts +8 -0
  51. package/lib/ProLayout/components/TabsManager/index.js +175 -0
  52. package/lib/ProLayout/components/TabsManager/propTypes.d.ts +74 -0
  53. package/lib/ProLayout/components/TabsManager/propTypes.js +22 -0
  54. package/lib/ProLayout/components/TabsManager/style/index.less +179 -0
  55. package/lib/ProLayout/components/TabsManager/utils/index.d.ts +38 -0
  56. package/lib/ProLayout/components/TabsManager/utils/index.js +119 -0
  57. package/lib/ProLayout/index.d.ts +10 -4
  58. package/lib/ProLayout/index.js +94 -8
  59. package/lib/ProLayout/propTypes.d.ts +139 -1
  60. package/lib/ProLayout/propTypes.js +40 -1
  61. package/lib/ProUpload/components/DragRender.d.ts +1 -0
  62. package/lib/ProUpload/components/DragRender.js +5 -1
  63. package/lib/ProUpload/index.js +4 -2
  64. package/lib/ProUpload/propsType.d.ts +5 -0
  65. package/lib/index.d.ts +2 -1
  66. package/lib/index.js +9 -2
  67. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ import { UseTabsStateOptions, UseTabsStateReturn } from '../propTypes';
2
+ /**
3
+ * 标签页状态管理Hook
4
+ */
5
+ export declare const useTabsState: (options: UseTabsStateOptions) => UseTabsStateReturn;
@@ -0,0 +1,364 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useTabsState = void 0;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
10
+ var _react = require("react");
11
+ var _propTypes = require("../propTypes");
12
+ var _useTabsCache2 = require("./useTabsCache");
13
+ var _utils = require("../utils");
14
+ /**
15
+ * 标签页状态管理Hook
16
+ */
17
+ var useTabsState = options => {
18
+ var _options$initialState = options.initialState,
19
+ initialState = _options$initialState === void 0 ? {} : _options$initialState,
20
+ config = options.config,
21
+ dataSource = options.dataSource;
22
+
23
+ // 合并默认配置
24
+ var finalConfig = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _propTypes.DEFAULT_TABS_CONFIG), config);
25
+
26
+ // 初始化状态
27
+ var _useState = (0, _react.useState)(() => (0, _objectSpread2.default)({
28
+ tabsList: [],
29
+ activeKey: '',
30
+ activeTabInfo: undefined,
31
+ newTabIndex: 0,
32
+ activeComponent: ''
33
+ }, initialState)),
34
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
35
+ state = _useState2[0],
36
+ setState = _useState2[1];
37
+
38
+ // 缓存管理
39
+ var _useTabsCache = (0, _useTabsCache2.useTabsCache)({
40
+ cacheKey: finalConfig.cacheKey,
41
+ storage: finalConfig.storage,
42
+ enabled: true
43
+ }),
44
+ saveToCache = _useTabsCache.saveToCache,
45
+ restoreFromCache = _useTabsCache.restoreFromCache,
46
+ clearCache = _useTabsCache.clearCache;
47
+
48
+ // 初始化标记,确保只在初始化后保存缓存
49
+ var _useState3 = (0, _react.useState)(false),
50
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
51
+ isInitialized = _useState4[0],
52
+ setIsInitialized = _useState4[1];
53
+
54
+ // 从缓存恢复状态
55
+ (0, _react.useEffect)(() => {
56
+ var cachedState = restoreFromCache();
57
+ if (cachedState && cachedState.tabsList && cachedState.tabsList.length > 0) {
58
+ // 兼容旧缓存:如果缓存中有 activeTab 但没有 activeTabInfo,进行迁移
59
+ var restoredState = (0, _objectSpread2.default)({}, cachedState);
60
+ if ('activeTab' in restoredState && !restoredState.activeTabInfo) {
61
+ restoredState.activeTabInfo = restoredState.activeTab;
62
+ delete restoredState.activeTab;
63
+ }
64
+ setState(restoredState);
65
+ }
66
+ setIsInitialized(true);
67
+ }, [restoreFromCache]);
68
+ var lastActiveKeyRef = (0, _react.useRef)('');
69
+ var shouldSkipSaveRef = (0, _react.useRef)(false);
70
+
71
+ // 保存状态到缓存
72
+ (0, _react.useEffect)(() => {
73
+ if (!isInitialized) return;
74
+
75
+ // 如果标记了跳过保存(清空缓存后),则跳过本次保存
76
+ if (shouldSkipSaveRef.current) {
77
+ shouldSkipSaveRef.current = false;
78
+ return;
79
+ }
80
+
81
+ // 处理 onTabChange 调用 - 支持空状态和正常切换
82
+ if (finalConfig.onTabChange && lastActiveKeyRef.current !== state.activeKey) {
83
+ lastActiveKeyRef.current = state.activeKey;
84
+ if (state.activeKey) {
85
+ // 正常的标签页切换
86
+ var activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
87
+ if (activeTab) {
88
+ finalConfig.onTabChange(state.activeKey, activeTab, state.tabsList);
89
+ }
90
+ } else {
91
+ // 空状态 - 所有标签页都被关闭
92
+ finalConfig.onTabChange('', undefined, state.tabsList);
93
+ }
94
+ }
95
+
96
+ // 如果 tabsList 为空且 activeKey 为空,说明是清空状态,不保存缓存
97
+ if (state.tabsList.length === 0 && !state.activeKey) {
98
+ return;
99
+ }
100
+
101
+ // 保存状态到缓存
102
+ saveToCache(state);
103
+ }, [state, saveToCache, finalConfig, isInitialized]);
104
+
105
+ /**
106
+ * 添加标签页
107
+ */
108
+ var addTab = (0, _react.useCallback)((menuItem, options) => {
109
+ var _ref = options || {},
110
+ _ref$forceNew = _ref.forceNew,
111
+ forceNew = _ref$forceNew === void 0 ? false : _ref$forceNew;
112
+ setState(prevState => {
113
+ // 只有最后一级菜单(叶子节点)才能添加标签页
114
+ if (!(0, _utils.isLeafMenuItem)(menuItem)) {
115
+ return prevState;
116
+ }
117
+
118
+ // 检查是否需要外部跳转
119
+ if ((0, _utils.shouldOpenExternal)(menuItem)) {
120
+ (0, _utils.handleExternalOpen)(menuItem);
121
+ return prevState;
122
+ }
123
+ var existingIds = prevState.tabsList.map(tab => tab.id);
124
+ var tabId = (0, _utils.generateTabId)(menuItem, existingIds);
125
+
126
+ // 如果 forceNew = false(默认),检查是否已存在相同的标签页
127
+ if (!forceNew) {
128
+ var existingTab = prevState.tabsList.find(tab => {
129
+ var _tab$menuItem;
130
+ return ((_tab$menuItem = tab.menuItem) === null || _tab$menuItem === void 0 ? void 0 : _tab$menuItem.code) === menuItem.code || tab.url === menuItem.url;
131
+ });
132
+ if (existingTab) {
133
+ var _existingTab$menuItem;
134
+ // 如果已存在,直接切换到该标签页
135
+ var _newState = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
136
+ activeKey: existingTab.id,
137
+ activeTabInfo: existingTab,
138
+ activeComponent: ((_existingTab$menuItem = existingTab.menuItem) === null || _existingTab$menuItem === void 0 ? void 0 : _existingTab$menuItem.code) || existingTab.id
139
+ });
140
+ return _newState;
141
+ }
142
+ }
143
+
144
+ // 检查是否超出限制
145
+ if ((0, _utils.checkTabLimit)(prevState.tabsList, finalConfig.max)) {
146
+ // 达到最大值时,不添加新标签页,直接返回
147
+ return prevState;
148
+ }
149
+
150
+ // 创建新标签页
151
+ var newTab = (0, _utils.createTabFromMenu)(menuItem, prevState.newTabIndex);
152
+ newTab.id = tabId;
153
+ var newState = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
154
+ tabsList: [...prevState.tabsList, newTab],
155
+ activeKey: tabId,
156
+ activeTabInfo: newTab,
157
+ newTabIndex: prevState.newTabIndex + 1,
158
+ activeComponent: menuItem.code || tabId
159
+ });
160
+ return newState;
161
+ });
162
+ }, [finalConfig]);
163
+
164
+ /**
165
+ * 移除标签页
166
+ */
167
+ var removeTab = (0, _react.useCallback)(tabId => {
168
+ setState(prevState => {
169
+ var tabToRemove = prevState.tabsList.find(tab => tab.id === tabId);
170
+ if (!tabToRemove || !tabToRemove.closable) {
171
+ return prevState;
172
+ }
173
+ var newTabs = prevState.tabsList.filter(tab => tab.id !== tabId);
174
+ var newActiveKey = prevState.activeKey;
175
+ var newActiveTabInfo = prevState.activeTabInfo;
176
+ var newActiveComponent = prevState.activeComponent;
177
+
178
+ // 如果移除的是当前活跃标签页,需要选择新的活跃标签页
179
+ if (prevState.activeKey === tabId && newTabs.length > 0) {
180
+ var _newActiveTabInfo$men;
181
+ var currentIndex = prevState.tabsList.findIndex(tab => tab.id === tabId);
182
+ var newActiveIndex = Math.min(currentIndex, newTabs.length - 1);
183
+ newActiveTabInfo = newTabs[newActiveIndex];
184
+ newActiveKey = newActiveTabInfo.id;
185
+ newActiveComponent = ((_newActiveTabInfo$men = newActiveTabInfo.menuItem) === null || _newActiveTabInfo$men === void 0 ? void 0 : _newActiveTabInfo$men.code) || newActiveTabInfo.id;
186
+ } else if (prevState.activeKey === tabId) {
187
+ // 如果删除后没有标签页了
188
+ newActiveKey = '';
189
+ newActiveTabInfo = undefined;
190
+ newActiveComponent = '';
191
+ }
192
+
193
+ // 如果删除后没有标签页了,清空缓存
194
+ if (newTabs.length === 0) {
195
+ // 标记跳过下次保存,避免清空后又被重新保存
196
+ shouldSkipSaveRef.current = true;
197
+ clearCache();
198
+
199
+ // 直接调用 onTabChange,因为 useEffect 会被跳过
200
+ if (finalConfig.onTabChange) {
201
+ console.log('[useTabsState] removeTab: Calling onTabChange with empty state');
202
+ setTimeout(() => {
203
+ finalConfig.onTabChange('', undefined, []);
204
+ }, 0);
205
+ }
206
+ }
207
+ return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
208
+ tabsList: newTabs,
209
+ activeKey: newActiveKey,
210
+ activeTabInfo: newActiveTabInfo,
211
+ activeComponent: newActiveComponent
212
+ });
213
+ });
214
+ }, [clearCache, finalConfig]);
215
+
216
+ /**
217
+ * 切换标签页
218
+ */
219
+ var switchTab = (0, _react.useCallback)(tabId => {
220
+ setState(prevState => {
221
+ var _targetTab$menuItem;
222
+ var targetTab = prevState.tabsList.find(tab => tab.id === tabId);
223
+ if (!targetTab) return prevState;
224
+ var newState = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
225
+ activeKey: tabId,
226
+ activeTabInfo: targetTab,
227
+ activeComponent: ((_targetTab$menuItem = targetTab.menuItem) === null || _targetTab$menuItem === void 0 ? void 0 : _targetTab$menuItem.code) || tabId
228
+ });
229
+ return newState;
230
+ });
231
+ }, []);
232
+
233
+ /**
234
+ * 关闭其他标签页
235
+ */
236
+ var closeOtherTabs = (0, _react.useCallback)(currentTabId => {
237
+ setState(prevState => {
238
+ var _currentTab$menuItem;
239
+ var currentTab = prevState.tabsList.find(tab => tab.id === currentTabId);
240
+ if (!currentTab) return prevState;
241
+
242
+ // 只保留当前标签页和不可关闭的标签页
243
+ var newTabs = prevState.tabsList.filter(tab => tab.id === currentTabId || !tab.closable);
244
+ return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
245
+ tabsList: newTabs,
246
+ activeKey: currentTabId,
247
+ activeTabInfo: currentTab,
248
+ activeComponent: ((_currentTab$menuItem = currentTab.menuItem) === null || _currentTab$menuItem === void 0 ? void 0 : _currentTab$menuItem.code) || currentTabId
249
+ });
250
+ });
251
+ }, []);
252
+
253
+ /**
254
+ * 关闭右侧标签页
255
+ */
256
+ var closeRightTabs = (0, _react.useCallback)(currentTabId => {
257
+ setState(prevState => {
258
+ var rightTabs = (0, _utils.getRightTabs)(prevState.tabsList, currentTabId);
259
+ var tabsToKeep = prevState.tabsList.filter(tab => !rightTabs.includes(tab) || !tab.closable);
260
+ return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
261
+ tabsList: tabsToKeep
262
+ });
263
+ });
264
+ }, []);
265
+
266
+ /**
267
+ * 关闭全部标签页
268
+ */
269
+ var closeAllTabs = (0, _react.useCallback)(() => {
270
+ setState(prevState => {
271
+ // 只保留不可关闭的标签页
272
+ var newTabs = prevState.tabsList.filter(tab => !tab.closable);
273
+ var newActiveKey = '';
274
+ var newActiveComponent = '';
275
+ if (newTabs.length > 0) {
276
+ var _firstTab$menuItem;
277
+ var firstTab = newTabs[0];
278
+ newActiveKey = firstTab.id;
279
+ newActiveComponent = ((_firstTab$menuItem = firstTab.menuItem) === null || _firstTab$menuItem === void 0 ? void 0 : _firstTab$menuItem.code) || firstTab.id;
280
+ }
281
+
282
+ // 关闭全部标签页时,清空缓存
283
+ // 标记跳过下次保存,避免清空后又被重新保存
284
+ shouldSkipSaveRef.current = true;
285
+ clearCache();
286
+
287
+ // 如果关闭后没有标签页了,直接调用 onTabChange
288
+ if (newTabs.length === 0 && finalConfig.onTabChange) {
289
+ console.log('[useTabsState] closeAllTabs: Calling onTabChange with empty state');
290
+ setTimeout(() => {
291
+ finalConfig.onTabChange('', undefined, []);
292
+ }, 0);
293
+ }
294
+ return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, prevState), {}, {
295
+ tabsList: newTabs,
296
+ activeKey: newActiveKey,
297
+ activeTabInfo: undefined,
298
+ activeComponent: newActiveComponent
299
+ });
300
+ });
301
+ }, [clearCache, finalConfig]);
302
+
303
+ /**
304
+ * 重置状态
305
+ */
306
+ var resetTabs = (0, _react.useCallback)(() => {
307
+ setState({
308
+ tabsList: [],
309
+ activeKey: '',
310
+ newTabIndex: 0,
311
+ activeComponent: ''
312
+ });
313
+ }, []);
314
+
315
+ // 监听 URL 变化并同步 Tabs (仅在初始化和 location 变化时)
316
+ // 放在最后以确保可以使用 addTab 和 switchTab
317
+ (0, _react.useEffect)(() => {
318
+ // 确保数据源存在
319
+ if (!dataSource || !('menus' in dataSource)) return;
320
+ var currentPath = window.location.pathname;
321
+
322
+ // 如果当前没有 activeKey 或者 activeKey 对应的 URL 与当前 URL 不一致
323
+ var activeTab = state.tabsList.find(tab => tab.id === state.activeKey);
324
+
325
+ // 如果当前已经在正确的 Tab 上,无需处理
326
+ if (activeTab && activeTab.url === currentPath) return;
327
+
328
+ // 在菜单中查找当前 URL 对应的菜单项
329
+ var flatMenus = (0, _utils.flattenMenuData)(dataSource.menus || []);
330
+ var targetMenu = flatMenus.find(item => item.url === currentPath);
331
+ if (targetMenu) {
332
+ // 只有最后一级菜单(叶子节点)才能添加标签页
333
+ if (!(0, _utils.isLeafMenuItem)(targetMenu)) {
334
+ return;
335
+ }
336
+
337
+ // 检查是否已在 Tabs 中
338
+ var existingTab = state.tabsList.find(tab => {
339
+ var _tab$menuItem2;
340
+ return ((_tab$menuItem2 = tab.menuItem) === null || _tab$menuItem2 === void 0 ? void 0 : _tab$menuItem2.code) === targetMenu.code || tab.url === targetMenu.url;
341
+ });
342
+ if (existingTab) {
343
+ // 如果已存在,切换到该 Tab
344
+ if (state.activeKey !== existingTab.id) {
345
+ switchTab(existingTab.id);
346
+ }
347
+ } else {
348
+ // 如果不存在,添加新 Tab
349
+ addTab(targetMenu);
350
+ }
351
+ }
352
+ }, [dataSource, state.tabsList, state.activeKey, addTab, switchTab]);
353
+ return {
354
+ state,
355
+ addTab,
356
+ removeTab,
357
+ switchTab,
358
+ closeOtherTabs,
359
+ closeRightTabs,
360
+ closeAllTabs,
361
+ resetTabs
362
+ };
363
+ };
364
+ exports.useTabsState = useTabsState;
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { TabsManagerProps } from './propTypes';
3
+ import './style/index.less';
4
+ /**
5
+ * 标签页管理器主组件
6
+ */
7
+ declare const TabsManager: import("react").ForwardRefExoticComponent<TabsManagerProps & import("react").RefAttributes<any>>;
8
+ export default TabsManager;
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _react = require("react");
11
+ var _useTabsState2 = require("./hooks/useTabsState");
12
+ var _TabItem = require("./components/TabItem");
13
+ var _TabsContext = require("./components/TabsContext");
14
+ require("./style/index.less");
15
+ var _jsxRuntime = require("react/jsx-runtime");
16
+ /**
17
+ * 标签页管理器主组件
18
+ */var TabsManager = /*#__PURE__*/(0, _react.forwardRef)((_ref, ref) => {
19
+ var config = _ref.config,
20
+ children = _ref.children,
21
+ dataSource = _ref.dataSource,
22
+ originalOnMenuClick = _ref.originalOnMenuClick;
23
+ // 使用标签页状态管理Hook
24
+ var _useTabsState = (0, _useTabsState2.useTabsState)({
25
+ config,
26
+ dataSource
27
+ }),
28
+ state = _useTabsState.state,
29
+ _addTab = _useTabsState.addTab,
30
+ removeTab = _useTabsState.removeTab,
31
+ switchTab = _useTabsState.switchTab,
32
+ closeOtherTabs = _useTabsState.closeOtherTabs,
33
+ closeRightTabs = _useTabsState.closeRightTabs,
34
+ closeAllTabs = _useTabsState.closeAllTabs;
35
+
36
+ // 记录已访问过的 Tab ID,用于懒加载
37
+ var _useState = (0, _react.useState)(new Set()),
38
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
39
+ visitedTabIds = _useState2[0],
40
+ setVisitedTabIds = _useState2[1];
41
+
42
+ // 监听 activeKey 变化,更新 visitedTabIds
43
+ (0, _react.useEffect)(() => {
44
+ if (state.activeKey) {
45
+ setVisitedTabIds(prev => {
46
+ if (prev.has(state.activeKey)) return prev;
47
+ var newSet = new Set(prev);
48
+ newSet.add(state.activeKey);
49
+ return newSet;
50
+ });
51
+ }
52
+ }, [state.activeKey]);
53
+
54
+ // 处理菜单点击 - 拦截原有的菜单点击逻辑
55
+ var handleMenuClick = (0, _react.useCallback)(params => {
56
+ if (params.item) {
57
+ // 添加到标签页
58
+ _addTab(params.item);
59
+ }
60
+
61
+ // 如果有原始的菜单点击处理函数,也调用它
62
+ originalOnMenuClick === null || originalOnMenuClick === void 0 || originalOnMenuClick(params);
63
+ }, [_addTab, originalOnMenuClick]);
64
+
65
+ // 获取当前激活的标签页
66
+ var activeTabInfo = (0, _react.useMemo)(() => {
67
+ return state.tabsList.find(tab => tab.id === state.activeKey);
68
+ }, [state.tabsList, state.activeKey]);
69
+
70
+ // 创建标签页实例 API
71
+ var tabsInstance = (0, _react.useMemo)(() => ({
72
+ addTab: (params, options) => {
73
+ var code = params.code,
74
+ name = params.name,
75
+ extra = params.extra;
76
+ var menuItem = {
77
+ id: Date.now(),
78
+ // 生成临时 ID
79
+ code,
80
+ name,
81
+ url: `/${code}`,
82
+ // 生成 URL
83
+ extra
84
+ };
85
+ _addTab(menuItem, options);
86
+ },
87
+ removeTab,
88
+ getTabInfo: () => ({
89
+ tabsList: state.tabsList,
90
+ activeTabInfo: state.tabsList.find(tab => tab.id === state.activeKey),
91
+ activeComponent: state.activeComponent
92
+ })
93
+ }), [_addTab, removeTab, state.tabsList, state.activeKey, state.activeComponent]);
94
+
95
+ // 渲染标签页列表
96
+ var renderTabList = () => {
97
+ if (state.tabsList.length === 0) return null;
98
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
99
+ className: "pro-layout-tabs-header",
100
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
101
+ className: "pro-layout-tab-list",
102
+ children: state.tabsList.map(tab => /*#__PURE__*/(0, _jsxRuntime.jsx)(_TabItem.TabItemComponent, {
103
+ tab: tab,
104
+ active: tab.id === state.activeKey,
105
+ onClick: () => switchTab(tab.id),
106
+ onClose: () => removeTab(tab.id),
107
+ onCloseOthers: () => closeOtherTabs(tab.id),
108
+ onCloseRight: () => closeRightTabs(tab.id),
109
+ onCloseAll: closeAllTabs,
110
+ tabsList: state.tabsList,
111
+ menuItems: config === null || config === void 0 ? void 0 : config.menuItems,
112
+ tabMenuClick: config === null || config === void 0 ? void 0 : config.tabMenuClick
113
+ }, tab.id))
114
+ })
115
+ });
116
+ };
117
+
118
+ // 从 config 中获取组件解析函数和空状态组件
119
+ var activeComponent = config === null || config === void 0 ? void 0 : config.activeComponent;
120
+ var emptyComponent = config === null || config === void 0 ? void 0 : config.empty;
121
+
122
+ // 渲染内容区域
123
+ var renderContent = () => {
124
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
125
+ className: "pro-layout-tabs-content",
126
+ children: [state.tabsList.map(tab => {
127
+ var _tab$menuItem;
128
+ var isActive = tab.id === state.activeKey;
129
+ var hasVisited = visitedTabIds.has(tab.id);
130
+
131
+ // 如果既不是当前激活,也没有访问过,则只渲染占位符(懒加载)
132
+ if (!isActive && !hasVisited) {
133
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
134
+ className: "tab-pane hidden",
135
+ "data-testid": `tab-pane-${tab.id}`
136
+ }, tab.id);
137
+ }
138
+ var content = children;
139
+
140
+ // 如果提供了组件解析函数,尝试解析组件
141
+ if (activeComponent && (_tab$menuItem = tab.menuItem) !== null && _tab$menuItem !== void 0 && _tab$menuItem.code) {
142
+ var ResolvedComponent = activeComponent(tab.menuItem.code);
143
+ if (ResolvedComponent) {
144
+ // 将 extra 中的所有属性作为 props 传递给组件
145
+ content = /*#__PURE__*/(0, _jsxRuntime.jsx)(ResolvedComponent, (0, _objectSpread2.default)({}, tab.menuItem.extra || {}));
146
+ }
147
+ }
148
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
149
+ className: `tab-pane ${isActive ? '' : 'hidden'}`,
150
+ "data-testid": `tab-pane-${tab.id}`,
151
+ children: content
152
+ }, tab.id);
153
+ }), state.tabsList.length === 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
154
+ className: "tab-pane",
155
+ "data-testid": "default-content",
156
+ children: emptyComponent || children
157
+ })]
158
+ });
159
+ };
160
+
161
+ // 暴露方法给父组件
162
+ (0, _react.useImperativeHandle)(ref, () => ({
163
+ handleMenuClick
164
+ }), [handleMenuClick]);
165
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_TabsContext.TabsContext.Provider, {
166
+ value: tabsInstance,
167
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
168
+ className: "pro-layout-tabs",
169
+ "data-testid": "tabs-manager",
170
+ children: [renderTabList(), renderContent()]
171
+ })
172
+ });
173
+ });
174
+ TabsManager.displayName = 'TabsManager';
175
+ var _default = exports.default = TabsManager;
@@ -0,0 +1,74 @@
1
+ import { ReactNode } from 'react';
2
+ import type { MenuProps } from 'antd';
3
+ import { TabsState, MenusType, DataSourceType, TabsConfig, AddTabOptions, TabItem } from '../../propTypes';
4
+ export interface TabsManagerProps {
5
+ /** 标签页配置 */
6
+ config: TabsConfig;
7
+ /** 子元素内容 */
8
+ children: ReactNode;
9
+ /** 菜单数据源 */
10
+ dataSource: DataSourceType | Partial<MenusType>;
11
+ /** 原始菜单点击处理 */
12
+ originalOnMenuClick?: (params: {
13
+ item: MenusType | null;
14
+ key: string;
15
+ keyPath: string[];
16
+ }) => void;
17
+ }
18
+ export interface TabContextMenuProps {
19
+ tabId: string;
20
+ children: React.ReactElement;
21
+ closable?: boolean;
22
+ onClose: (tabId: string) => void;
23
+ onCloseOthers: (tabId: string) => void;
24
+ onCloseRight: (tabId: string) => void;
25
+ onCloseAll: () => void;
26
+ /** 自定义菜单项,会与默认菜单项合并 */
27
+ menuItems?: MenuProps['items'];
28
+ /** 自定义菜单项点击回调 */
29
+ tabMenuClick?: (params: {
30
+ key: string;
31
+ tab: TabItem;
32
+ tabs: TabItem[];
33
+ }) => void;
34
+ /** 当前标签页信息 */
35
+ tab?: TabItem;
36
+ /** 所有标签页列表 */
37
+ tabs?: TabItem[];
38
+ }
39
+ export interface UseTabsStateOptions {
40
+ /** 初始状态 */
41
+ initialState?: Partial<TabsState>;
42
+ /** 配置 */
43
+ config: TabsManagerProps['config'];
44
+ /** 数据源 */
45
+ dataSource?: TabsManagerProps['dataSource'];
46
+ }
47
+ export interface UseTabsStateReturn {
48
+ /** 当前状态 */
49
+ state: TabsState;
50
+ /** 添加标签页 */
51
+ addTab: (menuItem: MenusType, options?: AddTabOptions) => void;
52
+ /** 移除标签页 */
53
+ removeTab: (tabId: string) => void;
54
+ /** 切换标签页 */
55
+ switchTab: (tabId: string) => void;
56
+ /** 关闭其他标签页 */
57
+ closeOtherTabs: (currentTabId: string) => void;
58
+ /** 关闭右侧标签页 */
59
+ closeRightTabs: (currentTabId: string) => void;
60
+ /** 关闭全部标签页 */
61
+ closeAllTabs: () => void;
62
+ /** 重置状态 */
63
+ resetTabs: () => void;
64
+ }
65
+ export interface TabsCacheManager {
66
+ save: (state: TabsState) => void;
67
+ restore: () => TabsState | null;
68
+ clear: () => void;
69
+ }
70
+ export declare const DEFAULT_TABS_CONFIG: {
71
+ max: number;
72
+ storage: "localStorage";
73
+ cacheKey: string;
74
+ };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DEFAULT_TABS_CONFIG = void 0;
7
+ // TabsManager组件Props
8
+
9
+ // 右键菜单组件Props
10
+
11
+ // 状态管理Hook选项
12
+
13
+ // 状态管理Hook返回值
14
+
15
+ // 缓存管理器接口
16
+
17
+ // 默认配置
18
+ var DEFAULT_TABS_CONFIG = exports.DEFAULT_TABS_CONFIG = {
19
+ max: 20,
20
+ storage: 'localStorage',
21
+ cacheKey: 'pro_layout_tabs'
22
+ };