@gx-design-vue/pro-layout 0.1.0-alpha.20 → 0.1.0-alpha.21
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/ProLayout.js +1 -1
- package/dist/components/Breadcrumb/index.js +3 -2
- package/dist/components/Breadcrumb/interface.d.ts +1 -1
- package/dist/components/Header/index.js +6 -14
- package/dist/components/Logo/index.js +6 -1
- package/dist/components/Menu/iconRender.d.ts +1 -1
- package/dist/components/Menu/iconRender.js +1 -1
- package/dist/components/Menu/index.d.ts +9 -10
- package/dist/components/Menu/index.js +670 -114
- package/dist/components/Menu/interface.d.ts +11 -11
- package/dist/components/Menu/interface.js +3 -3
- package/dist/components/Menu/overflow.d.ts +39 -0
- package/dist/components/Menu/overflow.js +81 -0
- package/dist/components/Menu/style/base.d.ts +12 -0
- package/dist/components/Menu/style/base.js +36 -0
- package/dist/components/Menu/style/horizontal.d.ts +19 -0
- package/dist/components/Menu/style/horizontal.js +303 -0
- package/dist/components/Menu/style/{siderMenu.d.ts → index.d.ts} +64 -5
- package/dist/components/Menu/style/index.js +147 -0
- package/dist/components/Menu/style/inline.d.ts +13 -0
- package/dist/components/Menu/style/{siderMenu.js → inline.js} +29 -115
- package/dist/components/PageContainer/index.js +2 -2
- package/dist/components/PageContainer/style.js +9 -6
- package/dist/components/Sider/index.js +18 -11
- package/dist/defaultConfig.js +1 -2
- package/dist/hooks/useLayoutBase.d.ts +15 -15
- package/dist/hooks/useMenu.d.ts +5 -5
- package/dist/hooks/useMenu.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/interface.d.ts +2 -6
- package/dist/interface.js +2 -2
- package/dist/pro-layout.esm.js +4777 -4469
- package/dist/pro-layout.js +3 -2
- package/dist/style/breadcrumb.js +2 -1
- package/dist/style/logo.js +6 -1
- package/dist/style/menu.d.ts +1 -1
- package/dist/style/menu.js +1 -1
- package/dist/theme/augment.d.ts +2 -2
- package/dist/theme/interface/components.d.ts +2 -2
- package/dist/utils/menu.d.ts +3 -3
- package/dist/utils/menu.js +2 -2
- package/dist/utils/themeComponents.d.ts +8 -4
- package/dist/utils/themeComponents.js +14 -4
- package/package.json +15 -15
- package/dist/components/Menu/SiderMenu.d.ts +0 -29
- package/dist/components/Menu/SiderMenu.js +0 -666
- package/dist/components/Menu/convert.d.ts +0 -14
- package/dist/components/Menu/convert.js +0 -50
|
@@ -1,666 +0,0 @@
|
|
|
1
|
-
import { useLayoutBase } from "../../hooks/useLayoutBase.js";
|
|
2
|
-
import { renderMenuIcon } from "./iconRender.js";
|
|
3
|
-
import { buildSiderProMenuTokens } from "../../utils/themeComponents.js";
|
|
4
|
-
import { LAYOUT_MENU_SLOT_KEYS } from "./interface.js";
|
|
5
|
-
import siderMenu_default from "./style/siderMenu.js";
|
|
6
|
-
import { Transition, computed, createVNode, defineComponent, isVNode, mergeProps, nextTick, onBeforeUnmount, ref, vShow, watch, withDirectives } from "vue";
|
|
7
|
-
import { useProToken } from "@gx-design-vue/pro-provider";
|
|
8
|
-
import { classNames, getSlotsProps } from "@gx-design-vue/pro-utils";
|
|
9
|
-
import { ConfigProvider, Popover } from "antdv-next";
|
|
10
|
-
import { useBaseConfig } from "antdv-next/config-provider/context";
|
|
11
|
-
import useCSSVarCls from "antdv-next/config-provider/hooks/useCSSVarCls";
|
|
12
|
-
import { omit } from "es-toolkit";
|
|
13
|
-
//#region src/components/Menu/SiderMenu.tsx
|
|
14
|
-
function _isSlot(s) {
|
|
15
|
-
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
16
|
-
}
|
|
17
|
-
const DEFAULT_INLINE_INDENT = 24;
|
|
18
|
-
const POPUP_CLOSE_DELAY = 120;
|
|
19
|
-
const SIDER_POPUP_BUILTIN_PLACEMENTS = { rightTop: {
|
|
20
|
-
points: ["tl", "tr"],
|
|
21
|
-
offset: [0, 0],
|
|
22
|
-
overflow: {
|
|
23
|
-
adjustX: true,
|
|
24
|
-
adjustY: true
|
|
25
|
-
},
|
|
26
|
-
autoArrow: false
|
|
27
|
-
} };
|
|
28
|
-
const SIDER_NESTED_POPUP_BUILTIN_PLACEMENTS = { rightTop: {
|
|
29
|
-
points: ["tl", "tr"],
|
|
30
|
-
offset: [-4, 0],
|
|
31
|
-
overflow: {
|
|
32
|
-
adjustX: true,
|
|
33
|
-
adjustY: true
|
|
34
|
-
},
|
|
35
|
-
autoArrow: false
|
|
36
|
-
} };
|
|
37
|
-
let hasSiderMenuInitialAutoScrolled = false;
|
|
38
|
-
function isPathPrefix(prefix, path) {
|
|
39
|
-
return prefix.length <= path.length && prefix.every((key, index) => key === path[index]);
|
|
40
|
-
}
|
|
41
|
-
function isSamePath(path, target) {
|
|
42
|
-
return path.length === target.length && isPathPrefix(path, target);
|
|
43
|
-
}
|
|
44
|
-
function getPathKey(path) {
|
|
45
|
-
return path.join("\0");
|
|
46
|
-
}
|
|
47
|
-
function getMenuTitleSymbol(title) {
|
|
48
|
-
return title ? title.charAt(0).toUpperCase() : null;
|
|
49
|
-
}
|
|
50
|
-
function getVisibleChildren(route) {
|
|
51
|
-
return route.children?.filter((child) => !child.meta?.hideInMenu) ?? [];
|
|
52
|
-
}
|
|
53
|
-
function hasSelectedDescendant(route, selectedKeys) {
|
|
54
|
-
if (selectedKeys.has(route.name)) return true;
|
|
55
|
-
return getVisibleChildren(route).some((child) => hasSelectedDescendant(child, selectedKeys));
|
|
56
|
-
}
|
|
57
|
-
function toMenuRenderItem(route, type) {
|
|
58
|
-
return {
|
|
59
|
-
key: route.name,
|
|
60
|
-
label: route.meta?.title,
|
|
61
|
-
icon: route.meta?.icon,
|
|
62
|
-
disabled: route.meta?.disabled,
|
|
63
|
-
title: route.meta?.title,
|
|
64
|
-
type,
|
|
65
|
-
route
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function getMenuRenderItemIcon(item, route) {
|
|
69
|
-
return item.icon ?? route.meta?.icon;
|
|
70
|
-
}
|
|
71
|
-
function resetCollapseStyle(el) {
|
|
72
|
-
el.style.maxHeight = "";
|
|
73
|
-
el.style.overflow = el.dataset.oldOverflow ?? "";
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Vue 3 <Transition> 在 JSX 中只认 onXxx 前缀的 props。
|
|
77
|
-
* 参考 Vue 源码 getTransitionRawProps —— 只收集 key.startsWith('on') 的函数。
|
|
78
|
-
*/
|
|
79
|
-
const collapseTransitionHooks = {
|
|
80
|
-
onBeforeEnter(el) {
|
|
81
|
-
const target = el;
|
|
82
|
-
target.dataset.oldOverflow = target.style.overflow;
|
|
83
|
-
target.style.maxHeight = "0";
|
|
84
|
-
target.style.overflow = "hidden";
|
|
85
|
-
},
|
|
86
|
-
onEnter(el) {
|
|
87
|
-
const target = el;
|
|
88
|
-
requestAnimationFrame(() => {
|
|
89
|
-
target.style.maxHeight = target.scrollHeight === 0 ? "0" : `${target.scrollHeight}px`;
|
|
90
|
-
target.style.overflow = "hidden";
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
onAfterEnter(el) {
|
|
94
|
-
resetCollapseStyle(el);
|
|
95
|
-
},
|
|
96
|
-
onEnterCancelled(el) {
|
|
97
|
-
resetCollapseStyle(el);
|
|
98
|
-
},
|
|
99
|
-
onBeforeLeave(el) {
|
|
100
|
-
const target = el;
|
|
101
|
-
target.dataset.oldOverflow = target.style.overflow;
|
|
102
|
-
target.style.maxHeight = `${target.scrollHeight}px`;
|
|
103
|
-
target.style.overflow = "hidden";
|
|
104
|
-
},
|
|
105
|
-
onLeave(el) {
|
|
106
|
-
const target = el;
|
|
107
|
-
if (target.scrollHeight !== 0) target.style.maxHeight = "0";
|
|
108
|
-
},
|
|
109
|
-
onAfterLeave(el) {
|
|
110
|
-
resetCollapseStyle(el);
|
|
111
|
-
},
|
|
112
|
-
onLeaveCancelled(el) {
|
|
113
|
-
resetCollapseStyle(el);
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
const SiderMenuContent = /* @__PURE__ */ defineComponent((props, { emit, slots }) => {
|
|
117
|
-
const { proClasses, proStyles, collapsed } = useLayoutBase(props);
|
|
118
|
-
const { prefixCls } = useBaseConfig("pro-sider-menu", props);
|
|
119
|
-
const rootCls = useCSSVarCls(prefixCls);
|
|
120
|
-
const [hashId, cssVarCls] = siderMenu_default(prefixCls, rootCls);
|
|
121
|
-
const { proLayoutToken } = useProToken();
|
|
122
|
-
const popupOpenPath = ref([]);
|
|
123
|
-
const menuRef = ref();
|
|
124
|
-
const hasInitialScrolled = ref(false);
|
|
125
|
-
const popupCloseTimers = /* @__PURE__ */ new Map();
|
|
126
|
-
const pendingPopupCloseKeys = /* @__PURE__ */ new Set();
|
|
127
|
-
let initialScrollFrame;
|
|
128
|
-
const selectedKeySet = computed(() => new Set(props.selectedKeys ?? []));
|
|
129
|
-
const openKeySet = computed(() => new Set(props.openKeys ?? []));
|
|
130
|
-
const customRenders = computed(() => getSlotsProps({
|
|
131
|
-
slots,
|
|
132
|
-
props,
|
|
133
|
-
keys: LAYOUT_MENU_SLOT_KEYS,
|
|
134
|
-
render: false
|
|
135
|
-
}));
|
|
136
|
-
const menuClassNames = computed(() => classNames(`${prefixCls.value}`, `${prefixCls.value}-root`, proClasses.value.menu, hashId.value, cssVarCls.value, rootCls.value, { [`${prefixCls.value}-collapsed`]: collapsed.value }, props.class));
|
|
137
|
-
const popupClassName = computed(() => classNames(`${prefixCls.value}-popover`, hashId.value, cssVarCls.value, rootCls.value));
|
|
138
|
-
function isPopupInteraction(ctx) {
|
|
139
|
-
return collapsed.value || ctx.popup;
|
|
140
|
-
}
|
|
141
|
-
function getPopupPath(route, ctx) {
|
|
142
|
-
return ctx.popup ? [...ctx.popupPath, route.name] : [route.name];
|
|
143
|
-
}
|
|
144
|
-
function isPopupPathOpen(path) {
|
|
145
|
-
return isPathPrefix(path, popupOpenPath.value);
|
|
146
|
-
}
|
|
147
|
-
function isSubMenuOpen(route, ctx) {
|
|
148
|
-
if (ctx.popup) return isPopupPathOpen(getPopupPath(route, ctx));
|
|
149
|
-
if (collapsed.value && ctx.depth === 0) return isPopupPathOpen([route.name]);
|
|
150
|
-
return openKeySet.value.has(route.name);
|
|
151
|
-
}
|
|
152
|
-
function getInlineIndent(route, ctx) {
|
|
153
|
-
return route.meta?.inlineIndent ?? ctx.inlineIndent;
|
|
154
|
-
}
|
|
155
|
-
function getItemStyle(route, ctx) {
|
|
156
|
-
const indent = getInlineIndent(route, ctx);
|
|
157
|
-
return {
|
|
158
|
-
"--pro-layout-sider-menu-level": ctx.depth,
|
|
159
|
-
"--pro-layout-sider-menu-indent": `${indent}px`
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
function emitOpenKeys(nextKeys) {
|
|
163
|
-
emit("openChange", nextKeys);
|
|
164
|
-
emit("update:openKeys", nextKeys);
|
|
165
|
-
}
|
|
166
|
-
function cancelPopupClose(path) {
|
|
167
|
-
(path ? Array.from({ length: path.length }, (_, index) => getPathKey(path.slice(0, index + 1))) : Array.from(popupCloseTimers.keys())).forEach((key) => {
|
|
168
|
-
const timer = popupCloseTimers.get(key);
|
|
169
|
-
if (timer !== void 0) {
|
|
170
|
-
clearTimeout(timer);
|
|
171
|
-
popupCloseTimers.delete(key);
|
|
172
|
-
}
|
|
173
|
-
pendingPopupCloseKeys.delete(key);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
function openPopupPath(path) {
|
|
177
|
-
cancelPopupClose(path);
|
|
178
|
-
popupOpenPath.value = path;
|
|
179
|
-
}
|
|
180
|
-
function closePopupPath(path) {
|
|
181
|
-
const key = getPathKey(path);
|
|
182
|
-
pendingPopupCloseKeys.delete(key);
|
|
183
|
-
if (isSamePath(path, popupOpenPath.value)) {
|
|
184
|
-
const nextPath = path.slice(0, -1);
|
|
185
|
-
popupOpenPath.value = nextPath;
|
|
186
|
-
const nextKey = getPathKey(nextPath);
|
|
187
|
-
if (nextPath.length > 0 && pendingPopupCloseKeys.has(nextKey)) closePopupPath(nextPath);
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
if (isPathPrefix(path, popupOpenPath.value)) pendingPopupCloseKeys.add(key);
|
|
191
|
-
}
|
|
192
|
-
function schedulePopupPathClose(path) {
|
|
193
|
-
const key = getPathKey(path);
|
|
194
|
-
cancelPopupClose(path);
|
|
195
|
-
const timer = setTimeout(() => {
|
|
196
|
-
popupCloseTimers.delete(key);
|
|
197
|
-
closePopupPath(path);
|
|
198
|
-
}, POPUP_CLOSE_DELAY);
|
|
199
|
-
popupCloseTimers.set(key, timer);
|
|
200
|
-
}
|
|
201
|
-
function clearPopupPath() {
|
|
202
|
-
cancelPopupClose();
|
|
203
|
-
pendingPopupCloseKeys.clear();
|
|
204
|
-
popupOpenPath.value = [];
|
|
205
|
-
}
|
|
206
|
-
function handleSubMenuClick(route, ctx) {
|
|
207
|
-
if (route.meta?.disabled) return;
|
|
208
|
-
if (isPopupInteraction(ctx)) {
|
|
209
|
-
openPopupPath(getPopupPath(route, ctx));
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
emitOpenKeys(openKeySet.value.has(route.name) ? (props.openKeys ?? []).filter((key) => key !== route.name) : [...props.openKeys ?? [], route.name]);
|
|
213
|
-
}
|
|
214
|
-
function handleItemClick(route, ctx) {
|
|
215
|
-
if (route.meta?.disabled) return;
|
|
216
|
-
const keyPath = [route.name, ...ctx.parentKeys].filter(Boolean);
|
|
217
|
-
const selectedKeys = [route.name];
|
|
218
|
-
emit("select", {
|
|
219
|
-
key: route.name,
|
|
220
|
-
keys: selectedKeys,
|
|
221
|
-
keyPath,
|
|
222
|
-
route
|
|
223
|
-
});
|
|
224
|
-
emit("update:selectedKeys", selectedKeys);
|
|
225
|
-
if (ctx.popup) clearPopupPath();
|
|
226
|
-
}
|
|
227
|
-
function handleKeydown(event, action) {
|
|
228
|
-
if (event.key !== "Enter" && event.key !== " ") return;
|
|
229
|
-
event.preventDefault();
|
|
230
|
-
action();
|
|
231
|
-
}
|
|
232
|
-
function scrollSelectedIntoView() {
|
|
233
|
-
if (hasInitialScrolled.value || hasSiderMenuInitialAutoScrolled || collapsed.value) return;
|
|
234
|
-
const menuEl = menuRef.value;
|
|
235
|
-
if (!menuEl) return;
|
|
236
|
-
const scrollContainer = props.getScrollContainer?.() ?? menuEl.closest(`.${prefixCls.value}-container`);
|
|
237
|
-
const selectedItem = menuEl.querySelector(`.${prefixCls.value}-item-selected`);
|
|
238
|
-
if (!scrollContainer || !selectedItem) return;
|
|
239
|
-
hasInitialScrolled.value = true;
|
|
240
|
-
hasSiderMenuInitialAutoScrolled = true;
|
|
241
|
-
const containerRect = scrollContainer.getBoundingClientRect();
|
|
242
|
-
const selectedRect = selectedItem.getBoundingClientRect();
|
|
243
|
-
if (selectedRect.top >= containerRect.top && selectedRect.bottom <= containerRect.bottom) return;
|
|
244
|
-
const nextTop = selectedRect.top - containerRect.top + scrollContainer.scrollTop - scrollContainer.clientHeight / 2 + selectedItem.offsetHeight / 2;
|
|
245
|
-
scrollContainer.scrollTo({
|
|
246
|
-
top: Math.max(0, nextTop),
|
|
247
|
-
behavior: "auto"
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
function scheduleInitialScroll() {
|
|
251
|
-
if (hasInitialScrolled.value || hasSiderMenuInitialAutoScrolled) return;
|
|
252
|
-
nextTick(() => {
|
|
253
|
-
if (hasInitialScrolled.value || hasSiderMenuInitialAutoScrolled) return;
|
|
254
|
-
if (initialScrollFrame !== void 0) cancelAnimationFrame(initialScrollFrame);
|
|
255
|
-
initialScrollFrame = requestAnimationFrame(() => {
|
|
256
|
-
initialScrollFrame = void 0;
|
|
257
|
-
scrollSelectedIntoView();
|
|
258
|
-
});
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
watch(() => [
|
|
262
|
-
props.menus?.length ?? 0,
|
|
263
|
-
props.selectedKeys?.join("|") ?? "",
|
|
264
|
-
props.openKeys?.join("|") ?? ""
|
|
265
|
-
], scheduleInitialScroll, {
|
|
266
|
-
immediate: true,
|
|
267
|
-
flush: "post"
|
|
268
|
-
});
|
|
269
|
-
onBeforeUnmount(() => {
|
|
270
|
-
if (initialScrollFrame !== void 0) cancelAnimationFrame(initialScrollFrame);
|
|
271
|
-
cancelPopupClose();
|
|
272
|
-
});
|
|
273
|
-
function renderIcon(route, item, firstLevelCollapsed) {
|
|
274
|
-
if (customRenders.value.menuItemIcon) return customRenders.value.menuItemIcon({
|
|
275
|
-
item,
|
|
276
|
-
route
|
|
277
|
-
});
|
|
278
|
-
const icon = renderMenuIcon(getMenuRenderItemIcon(item, route));
|
|
279
|
-
const iconNode = !icon && firstLevelCollapsed ? getMenuTitleSymbol(route.meta?.title) : icon;
|
|
280
|
-
if (!iconNode) return null;
|
|
281
|
-
return createVNode("span", {
|
|
282
|
-
"class": classNames(`${prefixCls.value}-icon`, route.meta?.classNames?.itemIcon),
|
|
283
|
-
"style": route.meta?.styles?.itemIcon
|
|
284
|
-
}, [iconNode]);
|
|
285
|
-
}
|
|
286
|
-
function renderLabel(route, item) {
|
|
287
|
-
if (customRenders.value.menuItemLabel) return customRenders.value.menuItemLabel({
|
|
288
|
-
item,
|
|
289
|
-
route
|
|
290
|
-
});
|
|
291
|
-
const label = route.meta?.classNames?.itemTitleText || route.meta?.styles?.itemTitleText ? createVNode("span", {
|
|
292
|
-
"class": route.meta?.classNames?.itemTitleText,
|
|
293
|
-
"style": route.meta?.styles?.itemTitleText
|
|
294
|
-
}, [item.label]) : item.label;
|
|
295
|
-
return createVNode("span", {
|
|
296
|
-
"class": classNames(`${prefixCls.value}-title`, route.meta?.classNames?.itemTitle),
|
|
297
|
-
"style": route.meta?.styles?.itemTitle
|
|
298
|
-
}, [label]);
|
|
299
|
-
}
|
|
300
|
-
function renderExtra(route, item) {
|
|
301
|
-
if (customRenders.value.menuItemExtra) return customRenders.value.menuItemExtra({
|
|
302
|
-
item,
|
|
303
|
-
route
|
|
304
|
-
});
|
|
305
|
-
if (!route.meta?.rightContent) return null;
|
|
306
|
-
const extra = route.meta.rightContent(route.meta);
|
|
307
|
-
if (extra == null || extra === false) return null;
|
|
308
|
-
return createVNode("span", {
|
|
309
|
-
"class": classNames(`${prefixCls.value}-extra`, route.meta.classNames?.itemRight),
|
|
310
|
-
"style": route.meta.styles?.itemRight
|
|
311
|
-
}, [extra]);
|
|
312
|
-
}
|
|
313
|
-
function renderMenuItem(route, ctx) {
|
|
314
|
-
const item = toMenuRenderItem(route, "item");
|
|
315
|
-
const firstLevelCollapsed = collapsed.value && !ctx.popup && ctx.depth === 0;
|
|
316
|
-
const selected = selectedKeySet.value.has(route.name);
|
|
317
|
-
const disabled = !!route.meta?.disabled;
|
|
318
|
-
return createVNode("li", {
|
|
319
|
-
"key": route.name,
|
|
320
|
-
"class": `${prefixCls.value}-node`,
|
|
321
|
-
"role": "none"
|
|
322
|
-
}, [createVNode("div", {
|
|
323
|
-
"class": classNames(`${prefixCls.value}-item`, route.meta?.classNames?.item, {
|
|
324
|
-
[`${prefixCls.value}-item-selected`]: selected,
|
|
325
|
-
[`${prefixCls.value}-item-disabled`]: disabled,
|
|
326
|
-
[`${prefixCls.value}-item-collapsed`]: firstLevelCollapsed
|
|
327
|
-
}),
|
|
328
|
-
"style": {
|
|
329
|
-
...getItemStyle(route, ctx),
|
|
330
|
-
...route.meta?.styles?.item
|
|
331
|
-
},
|
|
332
|
-
"role": "menuitem",
|
|
333
|
-
"tabindex": disabled ? -1 : 0,
|
|
334
|
-
"title": firstLevelCollapsed ? route.meta?.title : void 0,
|
|
335
|
-
"onClick": () => handleItemClick(route, ctx),
|
|
336
|
-
"onKeydown": (event) => handleKeydown(event, () => handleItemClick(route, ctx))
|
|
337
|
-
}, [
|
|
338
|
-
renderIcon(route, item, firstLevelCollapsed),
|
|
339
|
-
!firstLevelCollapsed && renderLabel(route, item),
|
|
340
|
-
!firstLevelCollapsed && renderExtra(route, item)
|
|
341
|
-
])]);
|
|
342
|
-
}
|
|
343
|
-
function renderSubMenuTitle(route, ctx, opened, active) {
|
|
344
|
-
const item = toMenuRenderItem(route, "submenu");
|
|
345
|
-
const firstLevelCollapsed = collapsed.value && !ctx.popup && ctx.depth === 0;
|
|
346
|
-
const disabled = !!route.meta?.disabled;
|
|
347
|
-
return createVNode("div", {
|
|
348
|
-
"class": classNames(`${prefixCls.value}-item`, `${prefixCls.value}-submenu-title`, {
|
|
349
|
-
[`${prefixCls.value}-item-open`]: opened,
|
|
350
|
-
[`${prefixCls.value}-item-active`]: active,
|
|
351
|
-
[`${prefixCls.value}-item-disabled`]: disabled,
|
|
352
|
-
[`${prefixCls.value}-item-collapsed`]: firstLevelCollapsed,
|
|
353
|
-
[`${prefixCls.value}-submenu-title-popup`]: ctx.popup
|
|
354
|
-
}),
|
|
355
|
-
"style": getItemStyle(route, ctx),
|
|
356
|
-
"role": "menuitem",
|
|
357
|
-
"aria-expanded": opened,
|
|
358
|
-
"tabindex": disabled ? -1 : 0,
|
|
359
|
-
"title": firstLevelCollapsed ? route.meta?.title : void 0,
|
|
360
|
-
"onClick": () => handleSubMenuClick(route, ctx),
|
|
361
|
-
"onKeydown": (event) => handleKeydown(event, () => handleSubMenuClick(route, ctx))
|
|
362
|
-
}, [
|
|
363
|
-
renderIcon(route, item, firstLevelCollapsed),
|
|
364
|
-
!firstLevelCollapsed && renderLabel(route, item),
|
|
365
|
-
!firstLevelCollapsed && renderExtra(route, item),
|
|
366
|
-
!firstLevelCollapsed && createVNode("i", { "class": `${prefixCls.value}-arrow` }, null)
|
|
367
|
-
]);
|
|
368
|
-
}
|
|
369
|
-
function renderSubMenu(route, children, ctx) {
|
|
370
|
-
let _slot;
|
|
371
|
-
const opened = isSubMenuOpen(route, ctx);
|
|
372
|
-
const active = hasSelectedDescendant(route, selectedKeySet.value);
|
|
373
|
-
const disabled = !!route.meta?.disabled;
|
|
374
|
-
const titleNode = renderSubMenuTitle(route, ctx, opened, active);
|
|
375
|
-
const nextCtx = {
|
|
376
|
-
depth: ctx.depth + 1,
|
|
377
|
-
parentKeys: [route.name, ...ctx.parentKeys],
|
|
378
|
-
popup: ctx.popup,
|
|
379
|
-
popupPath: ctx.popupPath,
|
|
380
|
-
inlineIndent: getInlineIndent(route, ctx)
|
|
381
|
-
};
|
|
382
|
-
if (collapsed.value && !ctx.popup && ctx.depth === 0 || ctx.popup) {
|
|
383
|
-
const popupPath = getPopupPath(route, ctx);
|
|
384
|
-
const popoverOpen = isPopupPathOpen(popupPath);
|
|
385
|
-
return createVNode("li", {
|
|
386
|
-
"key": route.name,
|
|
387
|
-
"class": classNames(`${prefixCls.value}-node`, `${prefixCls.value}-submenu`, route.meta?.classNames?.subMenu, {
|
|
388
|
-
[`${prefixCls.value}-submenu-open`]: popoverOpen,
|
|
389
|
-
[`${prefixCls.value}-submenu-active`]: active
|
|
390
|
-
}),
|
|
391
|
-
"style": route.meta?.styles?.subMenu,
|
|
392
|
-
"role": "none"
|
|
393
|
-
}, [createVNode(Popover, {
|
|
394
|
-
"trigger": "hover",
|
|
395
|
-
"placement": "rightTop",
|
|
396
|
-
"builtinPlacements": ctx.popup ? SIDER_NESTED_POPUP_BUILTIN_PLACEMENTS : SIDER_POPUP_BUILTIN_PLACEMENTS,
|
|
397
|
-
"arrow": false,
|
|
398
|
-
"open": popoverOpen,
|
|
399
|
-
"classes": {
|
|
400
|
-
root: classNames(popupClassName.value, `${prefixCls.value}-submenu-placement-rightTop`, { [`${prefixCls.value}-submenu-placement-nested`]: ctx.popup }, route.meta?.classNames?.subMenuPopup),
|
|
401
|
-
container: `${prefixCls.value}-popover-container`,
|
|
402
|
-
content: `${prefixCls.value}-popover-content`
|
|
403
|
-
},
|
|
404
|
-
"onOpenChange": (open) => {
|
|
405
|
-
if (disabled) return;
|
|
406
|
-
if (open) openPopupPath(popupPath);
|
|
407
|
-
else schedulePopupPathClose(popupPath);
|
|
408
|
-
}
|
|
409
|
-
}, {
|
|
410
|
-
default: () => [titleNode],
|
|
411
|
-
content: () => createVNode("div", { "class": `${prefixCls.value}-submenu-popup` }, [renderMenuList(children, {
|
|
412
|
-
depth: 0,
|
|
413
|
-
parentKeys: [route.name, ...ctx.parentKeys],
|
|
414
|
-
popup: true,
|
|
415
|
-
popupPath,
|
|
416
|
-
inlineIndent: getInlineIndent(route, ctx)
|
|
417
|
-
})])
|
|
418
|
-
})]);
|
|
419
|
-
}
|
|
420
|
-
return createVNode("li", {
|
|
421
|
-
"key": route.name,
|
|
422
|
-
"class": classNames(`${prefixCls.value}-node`, `${prefixCls.value}-submenu`, route.meta?.classNames?.subMenu, {
|
|
423
|
-
[`${prefixCls.value}-submenu-open`]: opened,
|
|
424
|
-
[`${prefixCls.value}-submenu-active`]: active
|
|
425
|
-
}),
|
|
426
|
-
"style": route.meta?.styles?.subMenu,
|
|
427
|
-
"role": "none"
|
|
428
|
-
}, [titleNode, createVNode(Transition, mergeProps({ "name": `${prefixCls.value}-collapse` }, collapseTransitionHooks), _isSlot(_slot = withDirectives(renderMenuList(children, nextCtx), [[vShow, opened]])) ? _slot : { default: () => [_slot] })]);
|
|
429
|
-
}
|
|
430
|
-
function renderGroup(route, children, ctx) {
|
|
431
|
-
const item = toMenuRenderItem(route, "group");
|
|
432
|
-
return createVNode("li", {
|
|
433
|
-
"key": route.name,
|
|
434
|
-
"class": classNames(`${prefixCls.value}-group`, route.meta?.classNames?.subMenu),
|
|
435
|
-
"style": route.meta?.styles?.subMenu,
|
|
436
|
-
"role": "presentation"
|
|
437
|
-
}, [createVNode("div", {
|
|
438
|
-
"class": `${prefixCls.value}-group-title`,
|
|
439
|
-
"style": getItemStyle(route, ctx)
|
|
440
|
-
}, [renderLabel(route, item)]), renderMenuList(children, {
|
|
441
|
-
depth: ctx.depth + 1,
|
|
442
|
-
parentKeys: [route.name, ...ctx.parentKeys],
|
|
443
|
-
popup: ctx.popup,
|
|
444
|
-
popupPath: ctx.popupPath,
|
|
445
|
-
inlineIndent: getInlineIndent(route, ctx)
|
|
446
|
-
})]);
|
|
447
|
-
}
|
|
448
|
-
function renderRoute(route, ctx) {
|
|
449
|
-
if (route.meta?.hideInMenu) return null;
|
|
450
|
-
const children = getVisibleChildren(route);
|
|
451
|
-
const divider = route.meta?.divider ? createVNode("li", {
|
|
452
|
-
"key": `${route.name}-divider`,
|
|
453
|
-
"class": `${prefixCls.value}-divider`,
|
|
454
|
-
"role": "separator"
|
|
455
|
-
}, null) : null;
|
|
456
|
-
const node = children.length > 0 ? route.meta?.menuItemType === "group" ? renderGroup(route, children, ctx) : renderSubMenu(route, children, ctx) : renderMenuItem(route, ctx);
|
|
457
|
-
return divider ? [divider, node] : node;
|
|
458
|
-
}
|
|
459
|
-
function renderMenuList(menus, ctx) {
|
|
460
|
-
return createVNode("ul", {
|
|
461
|
-
"class": classNames(`${prefixCls.value}`, {
|
|
462
|
-
[`${prefixCls.value}-sub`]: ctx.depth > 0 || ctx.popup,
|
|
463
|
-
[`${prefixCls.value}-popup-list`]: ctx.popup
|
|
464
|
-
}),
|
|
465
|
-
"role": ctx.popup ? "menu" : void 0
|
|
466
|
-
}, [menus.map((route) => renderRoute(route, ctx))]);
|
|
467
|
-
}
|
|
468
|
-
return () => {
|
|
469
|
-
const menus = props.menus ?? [];
|
|
470
|
-
if (menus.length === 0) return null;
|
|
471
|
-
return createVNode("ul", {
|
|
472
|
-
"ref": menuRef,
|
|
473
|
-
"class": menuClassNames.value,
|
|
474
|
-
"style": {
|
|
475
|
-
...props.style,
|
|
476
|
-
...proStyles.value.menu
|
|
477
|
-
},
|
|
478
|
-
"role": "menu",
|
|
479
|
-
"data-sider-menu-token-key": proLayoutToken.value.key
|
|
480
|
-
}, [menus.map((route) => renderRoute(route, {
|
|
481
|
-
depth: 0,
|
|
482
|
-
parentKeys: [],
|
|
483
|
-
popup: false,
|
|
484
|
-
popupPath: [],
|
|
485
|
-
inlineIndent: DEFAULT_INLINE_INDENT
|
|
486
|
-
}))]);
|
|
487
|
-
};
|
|
488
|
-
}, {
|
|
489
|
-
props: {
|
|
490
|
-
class: {
|
|
491
|
-
type: String,
|
|
492
|
-
required: false
|
|
493
|
-
},
|
|
494
|
-
prefixCls: {
|
|
495
|
-
type: String,
|
|
496
|
-
required: false
|
|
497
|
-
},
|
|
498
|
-
style: {
|
|
499
|
-
type: Object,
|
|
500
|
-
required: false
|
|
501
|
-
},
|
|
502
|
-
menus: {
|
|
503
|
-
type: Array,
|
|
504
|
-
required: false
|
|
505
|
-
},
|
|
506
|
-
selectedKeys: {
|
|
507
|
-
type: Array,
|
|
508
|
-
required: false
|
|
509
|
-
},
|
|
510
|
-
openKeys: {
|
|
511
|
-
type: Array,
|
|
512
|
-
required: false
|
|
513
|
-
},
|
|
514
|
-
collapsed: {
|
|
515
|
-
type: Boolean,
|
|
516
|
-
required: false,
|
|
517
|
-
default: void 0
|
|
518
|
-
},
|
|
519
|
-
proClasses: {
|
|
520
|
-
type: Object,
|
|
521
|
-
required: false
|
|
522
|
-
},
|
|
523
|
-
proStyles: {
|
|
524
|
-
type: Object,
|
|
525
|
-
required: false
|
|
526
|
-
},
|
|
527
|
-
getScrollContainer: {
|
|
528
|
-
type: Function,
|
|
529
|
-
required: false
|
|
530
|
-
},
|
|
531
|
-
menuItemIcon: {
|
|
532
|
-
type: Function,
|
|
533
|
-
required: false
|
|
534
|
-
},
|
|
535
|
-
menuItemLabel: {
|
|
536
|
-
type: Function,
|
|
537
|
-
required: false
|
|
538
|
-
},
|
|
539
|
-
menuItemExtra: {
|
|
540
|
-
type: Function,
|
|
541
|
-
required: false
|
|
542
|
-
},
|
|
543
|
-
onSelect: {
|
|
544
|
-
type: Function,
|
|
545
|
-
required: false
|
|
546
|
-
},
|
|
547
|
-
onOpenChange: {
|
|
548
|
-
type: Function,
|
|
549
|
-
required: false
|
|
550
|
-
},
|
|
551
|
-
"onUpdate:selectedKeys": {
|
|
552
|
-
type: Function,
|
|
553
|
-
required: false
|
|
554
|
-
},
|
|
555
|
-
"onUpdate:openKeys": {
|
|
556
|
-
type: Function,
|
|
557
|
-
required: false
|
|
558
|
-
}
|
|
559
|
-
},
|
|
560
|
-
emits: [
|
|
561
|
-
"select",
|
|
562
|
-
"openChange",
|
|
563
|
-
"update:selectedKeys",
|
|
564
|
-
"update:openKeys"
|
|
565
|
-
],
|
|
566
|
-
name: "SiderMenuContent",
|
|
567
|
-
inheritAttrs: false
|
|
568
|
-
});
|
|
569
|
-
const SiderMenu = /* @__PURE__ */ defineComponent((props, { emit, slots }) => {
|
|
570
|
-
const { token, proLayoutToken } = useProToken();
|
|
571
|
-
const siderProMenuTokens = computed(() => buildSiderProMenuTokens(proLayoutToken.value, token.value.Menu));
|
|
572
|
-
return () => createVNode(ConfigProvider, { "theme": { components: { ProSiderMenu: siderProMenuTokens.value } } }, { default: () => [createVNode(SiderMenuContent, mergeProps(omit(props, [
|
|
573
|
-
"onSelect",
|
|
574
|
-
"onOpenChange",
|
|
575
|
-
"onUpdate:selectedKeys",
|
|
576
|
-
"onUpdate:openKeys"
|
|
577
|
-
]), {
|
|
578
|
-
"onSelect": (info) => emit("select", info),
|
|
579
|
-
"onOpenChange": (keys) => emit("openChange", keys)
|
|
580
|
-
}, {
|
|
581
|
-
"onUpdate:selectedKeys": (keys) => emit("update:selectedKeys", keys),
|
|
582
|
-
"onUpdate:openKeys": (keys) => emit("update:openKeys", keys)
|
|
583
|
-
}), slots)] });
|
|
584
|
-
}, {
|
|
585
|
-
props: {
|
|
586
|
-
class: {
|
|
587
|
-
type: String,
|
|
588
|
-
required: false
|
|
589
|
-
},
|
|
590
|
-
prefixCls: {
|
|
591
|
-
type: String,
|
|
592
|
-
required: false
|
|
593
|
-
},
|
|
594
|
-
style: {
|
|
595
|
-
type: Object,
|
|
596
|
-
required: false
|
|
597
|
-
},
|
|
598
|
-
menus: {
|
|
599
|
-
type: Array,
|
|
600
|
-
required: false
|
|
601
|
-
},
|
|
602
|
-
selectedKeys: {
|
|
603
|
-
type: Array,
|
|
604
|
-
required: false
|
|
605
|
-
},
|
|
606
|
-
openKeys: {
|
|
607
|
-
type: Array,
|
|
608
|
-
required: false
|
|
609
|
-
},
|
|
610
|
-
collapsed: {
|
|
611
|
-
type: Boolean,
|
|
612
|
-
required: false,
|
|
613
|
-
default: void 0
|
|
614
|
-
},
|
|
615
|
-
proClasses: {
|
|
616
|
-
type: Object,
|
|
617
|
-
required: false
|
|
618
|
-
},
|
|
619
|
-
proStyles: {
|
|
620
|
-
type: Object,
|
|
621
|
-
required: false
|
|
622
|
-
},
|
|
623
|
-
getScrollContainer: {
|
|
624
|
-
type: Function,
|
|
625
|
-
required: false
|
|
626
|
-
},
|
|
627
|
-
menuItemIcon: {
|
|
628
|
-
type: Function,
|
|
629
|
-
required: false
|
|
630
|
-
},
|
|
631
|
-
menuItemLabel: {
|
|
632
|
-
type: Function,
|
|
633
|
-
required: false
|
|
634
|
-
},
|
|
635
|
-
menuItemExtra: {
|
|
636
|
-
type: Function,
|
|
637
|
-
required: false
|
|
638
|
-
},
|
|
639
|
-
onSelect: {
|
|
640
|
-
type: Function,
|
|
641
|
-
required: false
|
|
642
|
-
},
|
|
643
|
-
onOpenChange: {
|
|
644
|
-
type: Function,
|
|
645
|
-
required: false
|
|
646
|
-
},
|
|
647
|
-
"onUpdate:selectedKeys": {
|
|
648
|
-
type: Function,
|
|
649
|
-
required: false
|
|
650
|
-
},
|
|
651
|
-
"onUpdate:openKeys": {
|
|
652
|
-
type: Function,
|
|
653
|
-
required: false
|
|
654
|
-
}
|
|
655
|
-
},
|
|
656
|
-
emits: [
|
|
657
|
-
"select",
|
|
658
|
-
"openChange",
|
|
659
|
-
"update:selectedKeys",
|
|
660
|
-
"update:openKeys"
|
|
661
|
-
],
|
|
662
|
-
name: "SiderMenu",
|
|
663
|
-
inheritAttrs: false
|
|
664
|
-
});
|
|
665
|
-
//#endregion
|
|
666
|
-
export { SiderMenu as default };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { LayoutMenuRoute } from "../../interface.js";
|
|
2
|
-
import { MenuItemType } from "antdv-next";
|
|
3
|
-
|
|
4
|
-
//#region src/components/Menu/convert.d.ts
|
|
5
|
-
/**
|
|
6
|
-
* route 树 → antdv-next 数据驱动菜单项(纯数据,无 VNode)。
|
|
7
|
-
*
|
|
8
|
-
* 由 `LayoutMenu` 自洽持有(取代旧 `utils/menu.ts` 的 `toMenuItems` 与更旧的
|
|
9
|
-
* `MenuUtil.getNavMenuItems`):数据层只产路由分支,视觉转换归组件。
|
|
10
|
-
* 每个菜单项挂载原始 `route`,供 `iconRender`/`labelRender`/`extraRender` 读取 `meta`。
|
|
11
|
-
*/
|
|
12
|
-
declare function buildMenuItems(menus: LayoutMenuRoute[]): MenuItemType[];
|
|
13
|
-
//#endregion
|
|
14
|
-
export { buildMenuItems };
|