@tker-react/layout 0.2.5 → 0.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/dist/index.d.mts CHANGED
@@ -39,6 +39,10 @@ interface MenuAdapterProps {
39
39
  mode: "side" | "top";
40
40
  width: string;
41
41
  onSelect: (path: string) => void;
42
+ /** 当前展开的子菜单路径集合(side-menu 模式使用) */
43
+ openKeys: Set<string>;
44
+ /** 统一菜单点击入口,自动处理展开/折叠/导航,替代 onSelect 时 adapter 无需自行判断菜单类型 */
45
+ onMenuItemClick: (path: string) => void;
42
46
  }
43
47
  interface BreadcrumbAdapterProps {
44
48
  breadcrumbData: BreadcrumbItem[];
@@ -77,17 +81,11 @@ interface LayoutContextValue {
77
81
  setUserAvatarAdapter: (component: ComponentType<UserAvatarAdapterProps>) => void;
78
82
  menuData: MenuItem[];
79
83
  activePath: string;
80
- collapsed: boolean;
81
84
  expandedWidth: string;
82
85
  collapsedWidth: string;
83
86
  layoutMode: "side-menu" | "top-menu";
84
87
  setMenus: (data: MenuItem[]) => void;
85
88
  setActivePath: (path: string, fullPath?: string) => void;
86
- toggleCollapse: () => void;
87
- setCollapsed: (collapsed: boolean) => void;
88
- openKeys: Set<string>;
89
- toggleMenuOpen: (path: string, forceOpen?: boolean) => void;
90
- menuItemClick: (path: string) => void;
91
89
  setExpandedWidth: (width: string) => void;
92
90
  setCollapsedWidth: (width: string) => void;
93
91
  setLayoutMode: (mode: "side-menu" | "top-menu") => void;
@@ -105,5 +103,5 @@ declare function LayoutProvider({ children }: {
105
103
  children: ReactNode;
106
104
  }): react_jsx_runtime.JSX.Element;
107
105
 
108
- export { Layout, LayoutProvider, useLayoutContext as useLayout, useLayoutContext };
106
+ export { Layout, LayoutProvider, useLayoutContext as useLayout };
109
107
  export type { BreadcrumbAdapterProps, BreadcrumbItem, LayoutAdapters, LogoAdapterProps, MenuAdapterProps, MenuItem, TabAdapterProps, TabItem, UserAvatarAdapterProps };
package/dist/index.d.ts CHANGED
@@ -39,6 +39,10 @@ interface MenuAdapterProps {
39
39
  mode: "side" | "top";
40
40
  width: string;
41
41
  onSelect: (path: string) => void;
42
+ /** 当前展开的子菜单路径集合(side-menu 模式使用) */
43
+ openKeys: Set<string>;
44
+ /** 统一菜单点击入口,自动处理展开/折叠/导航,替代 onSelect 时 adapter 无需自行判断菜单类型 */
45
+ onMenuItemClick: (path: string) => void;
42
46
  }
43
47
  interface BreadcrumbAdapterProps {
44
48
  breadcrumbData: BreadcrumbItem[];
@@ -77,17 +81,11 @@ interface LayoutContextValue {
77
81
  setUserAvatarAdapter: (component: ComponentType<UserAvatarAdapterProps>) => void;
78
82
  menuData: MenuItem[];
79
83
  activePath: string;
80
- collapsed: boolean;
81
84
  expandedWidth: string;
82
85
  collapsedWidth: string;
83
86
  layoutMode: "side-menu" | "top-menu";
84
87
  setMenus: (data: MenuItem[]) => void;
85
88
  setActivePath: (path: string, fullPath?: string) => void;
86
- toggleCollapse: () => void;
87
- setCollapsed: (collapsed: boolean) => void;
88
- openKeys: Set<string>;
89
- toggleMenuOpen: (path: string, forceOpen?: boolean) => void;
90
- menuItemClick: (path: string) => void;
91
89
  setExpandedWidth: (width: string) => void;
92
90
  setCollapsedWidth: (width: string) => void;
93
91
  setLayoutMode: (mode: "side-menu" | "top-menu") => void;
@@ -105,5 +103,5 @@ declare function LayoutProvider({ children }: {
105
103
  children: ReactNode;
106
104
  }): react_jsx_runtime.JSX.Element;
107
105
 
108
- export { Layout, LayoutProvider, useLayoutContext as useLayout, useLayoutContext };
106
+ export { Layout, LayoutProvider, useLayoutContext as useLayout };
109
107
  export type { BreadcrumbAdapterProps, BreadcrumbItem, LayoutAdapters, LogoAdapterProps, MenuAdapterProps, MenuItem, TabAdapterProps, TabItem, UserAvatarAdapterProps };
package/dist/index.mjs CHANGED
@@ -44,6 +44,14 @@ function generateBreadcrumb(menuData, activePath) {
44
44
  }
45
45
 
46
46
  const LayoutContext = createContext(null);
47
+ const LayoutInteractionContext = createContext(null);
48
+ function useLayoutInteractionContext() {
49
+ const ctx = useContext(LayoutInteractionContext);
50
+ if (!ctx) {
51
+ throw new Error("useLayoutInteractionContext \u5FC5\u987B\u5728 <Layout> \u5185\u90E8\u4F7F\u7528");
52
+ }
53
+ return ctx;
54
+ }
47
55
  function useLayoutContext() {
48
56
  const ctx = useContext(LayoutContext);
49
57
  if (!ctx) {
@@ -107,6 +115,8 @@ function LayoutProvider({ children }) {
107
115
  collapsedRef.current = collapsed;
108
116
  const menuDataRef = useRef(menuData);
109
117
  menuDataRef.current = menuData;
118
+ const layoutModeRef = useRef(layoutMode);
119
+ layoutModeRef.current = layoutMode;
110
120
  const toggleMenuOpen = useCallback((path, forceOpen) => {
111
121
  setOpenKeys((prev) => {
112
122
  const next = new Set(prev);
@@ -125,7 +135,9 @@ function LayoutProvider({ children }) {
125
135
  const menuItemClick = useCallback((path) => {
126
136
  const item = findMenuItemByPath(menuDataRef.current, path);
127
137
  const hasChildren = !!(item?.children && item.children.length > 0);
138
+ const isSide = layoutModeRef.current === "side-menu";
128
139
  if (hasChildren) {
140
+ if (!isSide) return;
129
141
  if (collapsedRef.current) {
130
142
  setCollapsedState(false);
131
143
  const restored = new Set(savedOpenKeysRef.current);
@@ -183,6 +195,26 @@ function LayoutProvider({ children }) {
183
195
  const setMaxTabs = useCallback((max) => {
184
196
  setMaxTabsState(max);
185
197
  }, []);
198
+ const setCollapsed = useCallback((val) => {
199
+ if (val) {
200
+ savedOpenKeysRef.current = new Set(openKeysRef.current);
201
+ setOpenKeys(/* @__PURE__ */ new Set());
202
+ } else {
203
+ setOpenKeys(new Set(savedOpenKeysRef.current));
204
+ }
205
+ setCollapsedState(val);
206
+ }, []);
207
+ const interactionValue = useMemo(
208
+ () => ({
209
+ collapsed,
210
+ toggleCollapse,
211
+ setCollapsed,
212
+ openKeys,
213
+ toggleMenuOpen,
214
+ menuItemClick
215
+ }),
216
+ [collapsed, toggleCollapse, setCollapsed, openKeys, toggleMenuOpen, menuItemClick]
217
+ );
186
218
  const value = useMemo(
187
219
  () => ({
188
220
  adapters,
@@ -194,26 +226,11 @@ function LayoutProvider({ children }) {
194
226
  setUserAvatarAdapter,
195
227
  menuData,
196
228
  activePath,
197
- collapsed,
198
229
  expandedWidth,
199
230
  collapsedWidth,
200
231
  layoutMode,
201
232
  setMenus,
202
233
  setActivePath,
203
- toggleCollapse,
204
- // setCollapsed 同样处理 openKeys 保存/恢复,与 toggleCollapse 逻辑一致
205
- setCollapsed: (val) => {
206
- if (val) {
207
- savedOpenKeysRef.current = new Set(openKeysRef.current);
208
- setOpenKeys(/* @__PURE__ */ new Set());
209
- } else {
210
- setOpenKeys(new Set(savedOpenKeysRef.current));
211
- }
212
- setCollapsedState(val);
213
- },
214
- openKeys,
215
- toggleMenuOpen,
216
- menuItemClick,
217
234
  setExpandedWidth,
218
235
  setCollapsedWidth,
219
236
  setLayoutMode,
@@ -236,16 +253,11 @@ function LayoutProvider({ children }) {
236
253
  setUserAvatarAdapter,
237
254
  menuData,
238
255
  activePath,
239
- collapsed,
240
256
  expandedWidth,
241
257
  collapsedWidth,
242
258
  layoutMode,
243
259
  setMenus,
244
260
  setActivePath,
245
- toggleCollapse,
246
- openKeys,
247
- toggleMenuOpen,
248
- menuItemClick,
249
261
  isConcretePage,
250
262
  getFullPath,
251
263
  setNavigateAdapter,
@@ -256,22 +268,21 @@ function LayoutProvider({ children }) {
256
268
  setMaxTabs
257
269
  ]
258
270
  );
259
- return /* @__PURE__ */ jsx(LayoutContext.Provider, { value, children });
271
+ return /* @__PURE__ */ jsx(LayoutContext.Provider, { value, children: /* @__PURE__ */ jsx(LayoutInteractionContext.Provider, { value: interactionValue, children }) });
260
272
  }
261
273
 
262
274
  function LayoutAside() {
263
275
  const {
264
276
  adapters,
265
- collapsed,
266
277
  expandedWidth,
267
278
  collapsedWidth,
268
279
  menuData,
269
280
  activePath,
270
281
  layoutMode,
271
282
  getFullPath,
272
- navigate,
273
- toggleCollapse
283
+ navigate
274
284
  } = useLayoutContext();
285
+ const { collapsed, toggleCollapse, openKeys, menuItemClick } = useLayoutInteractionContext();
275
286
  const menuMode = layoutMode === "top-menu" ? "top" : "side";
276
287
  const handleMenuSelect = useCallback(
277
288
  (path) => {
@@ -293,7 +304,9 @@ function LayoutAside() {
293
304
  collapsed,
294
305
  mode: menuMode,
295
306
  width: asideWidth,
296
- onSelect: handleMenuSelect
307
+ openKeys,
308
+ onSelect: handleMenuSelect,
309
+ onMenuItemClick: menuItemClick
297
310
  }
298
311
  ),
299
312
  /* @__PURE__ */ jsx(
@@ -484,7 +497,6 @@ function openTabInData(tabData, path, config) {
484
497
  function LayoutHeader() {
485
498
  const {
486
499
  adapters,
487
- collapsed,
488
500
  expandedWidth,
489
501
  collapsedWidth,
490
502
  menuData,
@@ -494,6 +506,7 @@ function LayoutHeader() {
494
506
  isConcretePage,
495
507
  navigate
496
508
  } = useLayoutContext();
509
+ const { collapsed, menuItemClick } = useLayoutInteractionContext();
497
510
  const isTopMenu = layoutMode === "top-menu";
498
511
  const isSideMenu = layoutMode === "side-menu";
499
512
  const breadcrumbData = useMemo(
@@ -542,7 +555,9 @@ function LayoutHeader() {
542
555
  collapsed: false,
543
556
  mode: "top",
544
557
  width: logoWidth,
545
- onSelect: handleMenuSelect
558
+ openKeys: /* @__PURE__ */ new Set(),
559
+ onSelect: handleMenuSelect,
560
+ onMenuItemClick: menuItemClick
546
561
  }
547
562
  ),
548
563
  BreadcrumbAdapter && isSideMenu && /* @__PURE__ */ jsx(
@@ -575,4 +590,4 @@ function Layout({ children }) {
575
590
  return /* @__PURE__ */ jsx(LayoutProvider, { children: /* @__PURE__ */ jsx(LayoutInner, { children }) });
576
591
  }
577
592
 
578
- export { Layout, LayoutProvider, useLayoutContext as useLayout, useLayoutContext };
593
+ export { Layout, LayoutProvider, useLayoutContext as useLayout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tker-react/layout",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",