@zat-design/sisyphus-react 4.1.0 → 4.1.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.
- package/dist/index.esm.css +1 -1
- package/dist/less.esm.css +1 -1
- package/es/ProForm/components/combination/Group/utils/index.d.ts +7 -7
- package/es/ProLayout/components/Layout/Menu/OpenMenu/index.js +4 -1
- package/es/ProLayout/components/Layout/Menu/OpenMenu/style/index.less +13 -1
- package/es/ProLayout/components/Layout/Menu/SideMenu/style/index.less +16 -1
- package/es/ProLayout/components/Layout/Menu/index.js +104 -1
- package/lib/ProForm/components/combination/Group/utils/index.d.ts +14 -14
- package/lib/ProLayout/components/Layout/Menu/OpenMenu/index.js +4 -1
- package/lib/ProLayout/components/Layout/Menu/OpenMenu/style/index.less +13 -1
- package/lib/ProLayout/components/Layout/Menu/SideMenu/style/index.less +16 -1
- package/lib/ProLayout/components/Layout/Menu/index.js +104 -3
- package/package.json +2 -1
|
@@ -75,14 +75,14 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
75
75
|
confirm?: boolean | import("antd").ModalFuncProps | import("../../../render/propsType").FunctionArgs<any, boolean | import("antd").ModalFuncProps>;
|
|
76
76
|
show?: boolean | ReactiveFunction<any, boolean>;
|
|
77
77
|
component?: React.ReactNode | ReactiveFunction<any, React.ReactNode>;
|
|
78
|
-
style?: React.CSSProperties;
|
|
79
|
-
id?: string;
|
|
80
|
-
children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
|
|
81
78
|
trim?: boolean;
|
|
82
79
|
normalize?: (value: any, prevValue: any, allValues: import("@rc-component/form/lib/interface").Store) => any;
|
|
83
|
-
|
|
80
|
+
children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
|
|
84
81
|
vertical?: boolean;
|
|
82
|
+
id?: string;
|
|
83
|
+
className?: string;
|
|
85
84
|
hidden?: boolean;
|
|
85
|
+
style?: React.CSSProperties;
|
|
86
86
|
onReset?: () => void;
|
|
87
87
|
prefixCls?: string;
|
|
88
88
|
rootClassName?: string;
|
|
@@ -92,9 +92,6 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
92
92
|
isView?: boolean;
|
|
93
93
|
desensitization?: [number, number] | ReactiveFunction<any, [number, number]>;
|
|
94
94
|
getValueProps?: ((value: any) => Record<string, unknown>) & ((value: any) => Record<string, unknown>);
|
|
95
|
-
layout?: import("antd/es/form/Form").FormItemLayout;
|
|
96
|
-
help?: React.ReactNode;
|
|
97
|
-
preserve?: boolean;
|
|
98
95
|
htmlFor?: string;
|
|
99
96
|
labelAlign?: import("antd/es/form/interface").FormLabelAlign;
|
|
100
97
|
labelCol?: import("antd").ColProps;
|
|
@@ -106,6 +103,7 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
106
103
|
messageVariables?: Record<string, string>;
|
|
107
104
|
initialValue?: any;
|
|
108
105
|
onMetaChange?: (meta: import("@rc-component/form/lib/Field").MetaEvent) => void;
|
|
106
|
+
preserve?: boolean;
|
|
109
107
|
isListField?: boolean;
|
|
110
108
|
isList?: boolean;
|
|
111
109
|
noStyle?: boolean;
|
|
@@ -113,7 +111,9 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
113
111
|
icons: import("antd/es/form/FormItem").FeedbackIcons;
|
|
114
112
|
};
|
|
115
113
|
validateStatus?: "" | "success" | "error" | "warning" | "validating";
|
|
114
|
+
layout?: import("antd/es/form/Form").FormItemLayout;
|
|
116
115
|
wrapperCol?: import("antd").ColProps;
|
|
116
|
+
help?: React.ReactNode;
|
|
117
117
|
fieldId?: string;
|
|
118
118
|
valueType?: import("../../../render/propsType").ProFormValueType;
|
|
119
119
|
switchValue?: [any, any];
|
|
@@ -24,7 +24,9 @@ var OpenMenu = props => {
|
|
|
24
24
|
var className = props.className,
|
|
25
25
|
dataSource = props.dataSource,
|
|
26
26
|
style = props.style,
|
|
27
|
-
onMenuClick = props.onMenuClick
|
|
27
|
+
onMenuClick = props.onMenuClick,
|
|
28
|
+
_props$textVisible = props.textVisible,
|
|
29
|
+
textVisible = _props$textVisible === void 0 ? true : _props$textVisible;
|
|
28
30
|
var _ref = dataSource || {},
|
|
29
31
|
menus = _ref.menus,
|
|
30
32
|
sideMenu = _ref.sideMenu;
|
|
@@ -48,6 +50,7 @@ var OpenMenu = props => {
|
|
|
48
50
|
var layoutTarget = layoutContext === null || layoutContext === void 0 ? void 0 : layoutContext.target;
|
|
49
51
|
var cls = classnames({
|
|
50
52
|
'pro-layout-open-menu': true,
|
|
53
|
+
'pro-layout-menu-text-hidden': textVisible === false,
|
|
51
54
|
[`${className}`]: className
|
|
52
55
|
});
|
|
53
56
|
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
@import '../../../../../../style/variables.less';
|
|
2
2
|
|
|
3
3
|
.pro-layout-open-menu {
|
|
4
|
+
// 展开动画期间(Menu 传入 textVisible=false)隐藏文字,避免”挤压式逐字出现”;宽度过渡结束后再淡入
|
|
5
|
+
&.pro-layout-menu-text-hidden {
|
|
6
|
+
.@{ant-prefix}-menu-title-content {
|
|
7
|
+
div {
|
|
8
|
+
h2 {
|
|
9
|
+
opacity: 0 !important;
|
|
10
|
+
transition: none !important; // 确保隐藏时无过渡动画
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
|
|
5
16
|
.@{ant-prefix}-menu-root {
|
|
6
17
|
overflow-y: auto !important;
|
|
@@ -98,7 +109,8 @@
|
|
|
98
109
|
font-weight: 400;
|
|
99
110
|
font-size: var(--zaui-font-size-md, 14px);
|
|
100
111
|
opacity: 1;
|
|
101
|
-
|
|
112
|
+
// 修改:添加 150ms 的 opacity 淡入动画,消除"突然出现"的卡顿感
|
|
113
|
+
transition: opacity 0.15s ease-out, margin 0.3s, color 0.3s;
|
|
102
114
|
}
|
|
103
115
|
}
|
|
104
116
|
}
|
|
@@ -78,9 +78,24 @@
|
|
|
78
78
|
overflow-x: hidden;
|
|
79
79
|
overflow-y: auto;
|
|
80
80
|
|
|
81
|
+
// 与展开态一致:hover 使用透明背景 + 左侧品牌色半透明条
|
|
81
82
|
.@{ant-prefix}-menu-submenu-title:hover,
|
|
82
83
|
.@{ant-prefix}-menu-item:hover {
|
|
83
|
-
|
|
84
|
+
position: relative;
|
|
85
|
+
background-color: transparent !important;
|
|
86
|
+
|
|
87
|
+
&::before {
|
|
88
|
+
position: absolute;
|
|
89
|
+
left: var(--zaui-space-size-sm, 8px);
|
|
90
|
+
right: var(--zaui-space-size-sm, 8px);
|
|
91
|
+
width: auto;
|
|
92
|
+
min-height: 38px;
|
|
93
|
+
height: 80%;
|
|
94
|
+
background-color: var(--zaui-brand, #006aff);
|
|
95
|
+
border-radius: var(--zaui-border-radius, 8px);
|
|
96
|
+
opacity: 0.08;
|
|
97
|
+
content: '';
|
|
98
|
+
}
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
.@{ant-prefix}-menu-item {
|
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import { useEffect, useRef, useState, useCallback } from 'react';
|
|
1
8
|
import classnames from 'classnames';
|
|
2
9
|
import OpenMenu from "./OpenMenu";
|
|
3
10
|
import FoldMenu from "./FoldMenu"; // 折叠后菜单
|
|
4
11
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
5
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
13
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
+
// 菜单宽度配置
|
|
15
|
+
var MENU_CONFIG = {
|
|
16
|
+
TRANSITION_DURATION: 300,
|
|
17
|
+
// 宽度过渡时长(ms)
|
|
18
|
+
TEXT_VISIBLE_THRESHOLD: 150,
|
|
19
|
+
// 文字显示阈值(px, 约68%展开)
|
|
20
|
+
FULL_WIDTH: 219 // 完全展开宽度(px)
|
|
21
|
+
};
|
|
7
22
|
var Menu = props => {
|
|
8
23
|
var _ref = props || {},
|
|
9
24
|
headerHeight = _ref.headerHeight,
|
|
@@ -17,6 +32,83 @@ var Menu = props => {
|
|
|
17
32
|
sideMenuHeaderRender = _ref.sideMenuHeaderRender,
|
|
18
33
|
onMenuClick = _ref.onMenuClick;
|
|
19
34
|
var menus = [];
|
|
35
|
+
var menuRef = useRef(null);
|
|
36
|
+
// 整合所有动画相关的refs
|
|
37
|
+
var animationStateRef = useRef({
|
|
38
|
+
timer: null,
|
|
39
|
+
observer: null,
|
|
40
|
+
hasTriggered: false
|
|
41
|
+
});
|
|
42
|
+
var _useState = useState(false),
|
|
43
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
44
|
+
isOpenMenuTextVisible = _useState2[0],
|
|
45
|
+
setIsOpenMenuTextVisible = _useState2[1];
|
|
46
|
+
|
|
47
|
+
// 提取清理逻辑
|
|
48
|
+
var cleanupAnimation = useCallback(() => {
|
|
49
|
+
var state = animationStateRef.current;
|
|
50
|
+
if (state.timer) {
|
|
51
|
+
clearTimeout(state.timer);
|
|
52
|
+
state.timer = null;
|
|
53
|
+
}
|
|
54
|
+
if (state.observer) {
|
|
55
|
+
try {
|
|
56
|
+
state.observer.disconnect();
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.warn('ResizeObserver disconnect failed:', e);
|
|
59
|
+
}
|
|
60
|
+
state.observer = null;
|
|
61
|
+
}
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
// 触发文字显示
|
|
65
|
+
var showMenuText = useCallback(() => {
|
|
66
|
+
var state = animationStateRef.current;
|
|
67
|
+
if (state.hasTriggered) return;
|
|
68
|
+
state.hasTriggered = true;
|
|
69
|
+
setIsOpenMenuTextVisible(true);
|
|
70
|
+
// 延迟清理,避免回调内竞态
|
|
71
|
+
setTimeout(cleanupAnimation, 0);
|
|
72
|
+
}, [cleanupAnimation]);
|
|
73
|
+
|
|
74
|
+
// ResizeObserver 监听宽度变化,提前显示文字
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
var _menuRef$current$getB, _menuRef$current, _menuRef$current$getB2;
|
|
77
|
+
var state = animationStateRef.current;
|
|
78
|
+
state.hasTriggered = false;
|
|
79
|
+
|
|
80
|
+
// 折叠态:清理并隐藏文字
|
|
81
|
+
if (!collapsed) {
|
|
82
|
+
setIsOpenMenuTextVisible(false);
|
|
83
|
+
cleanupAnimation();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 检查是否已展开
|
|
88
|
+
var currentWidth = (_menuRef$current$getB = (_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 || (_menuRef$current$getB2 = _menuRef$current.getBoundingClientRect) === null || _menuRef$current$getB2 === void 0 ? void 0 : _menuRef$current$getB2.call(_menuRef$current).width) !== null && _menuRef$current$getB !== void 0 ? _menuRef$current$getB : 0;
|
|
89
|
+
if (currentWidth >= MENU_CONFIG.FULL_WIDTH) {
|
|
90
|
+
state.hasTriggered = true;
|
|
91
|
+
setIsOpenMenuTextVisible(true);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 创建 ResizeObserver
|
|
96
|
+
var supportsResizeObserver = typeof ResizeObserver !== 'undefined';
|
|
97
|
+
if (supportsResizeObserver && menuRef.current) {
|
|
98
|
+
state.observer = new ResizeObserver(entries => {
|
|
99
|
+
var _entries$0$contentRec, _entries$;
|
|
100
|
+
var width = (_entries$0$contentRec = (_entries$ = entries[0]) === null || _entries$ === void 0 ? void 0 : _entries$.contentRect.width) !== null && _entries$0$contentRec !== void 0 ? _entries$0$contentRec : 0;
|
|
101
|
+
if (width >= MENU_CONFIG.TEXT_VISIBLE_THRESHOLD) {
|
|
102
|
+
showMenuText();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
state.observer.observe(menuRef.current);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Fallback:定时器保底
|
|
109
|
+
state.timer = setTimeout(showMenuText, MENU_CONFIG.TRANSITION_DURATION);
|
|
110
|
+
return cleanupAnimation;
|
|
111
|
+
}, [collapsed, cleanupAnimation, showMenuText]);
|
|
20
112
|
var menuCls = classnames({
|
|
21
113
|
'pro-layout-menu': true,
|
|
22
114
|
'pro-layout-menu-open': collapsed
|
|
@@ -30,10 +122,17 @@ var Menu = props => {
|
|
|
30
122
|
return /*#__PURE__*/_jsx(_Fragment, {});
|
|
31
123
|
}
|
|
32
124
|
return /*#__PURE__*/_jsxs("div", {
|
|
125
|
+
ref: menuRef,
|
|
33
126
|
className: menuCls,
|
|
34
127
|
style: {
|
|
35
128
|
top: notice ? 96 + headerHeight - 64 : headerHeight
|
|
36
129
|
},
|
|
130
|
+
onTransitionEnd: e => {
|
|
131
|
+
// Fallback:确保宽度过渡结束后文字一定显示
|
|
132
|
+
if (e.propertyName === 'width' && e.target === menuRef.current && collapsed) {
|
|
133
|
+
showMenuText();
|
|
134
|
+
}
|
|
135
|
+
},
|
|
37
136
|
children: [sideMenuHeaderRender, /*#__PURE__*/_jsx(OpenMenu, {
|
|
38
137
|
dataSource: {
|
|
39
138
|
menus,
|
|
@@ -41,6 +140,7 @@ var Menu = props => {
|
|
|
41
140
|
height: headerHeight + (notice ? 32 : 0) + 48
|
|
42
141
|
},
|
|
43
142
|
onMenuClick: onMenuClick,
|
|
143
|
+
textVisible: isOpenMenuTextVisible,
|
|
44
144
|
style: {
|
|
45
145
|
display: collapsed ? 'block' : 'none'
|
|
46
146
|
}
|
|
@@ -60,7 +160,10 @@ var Menu = props => {
|
|
|
60
160
|
}
|
|
61
161
|
}), sideMenuFooterRender || /*#__PURE__*/_jsx("div", {
|
|
62
162
|
className: "pro-layout-menu-collapsed",
|
|
63
|
-
onClick:
|
|
163
|
+
onClick: () => {
|
|
164
|
+
setIsOpenMenuTextVisible(false);
|
|
165
|
+
onToggle === null || onToggle === void 0 || onToggle();
|
|
166
|
+
},
|
|
64
167
|
children: /*#__PURE__*/_jsx("div", {
|
|
65
168
|
className: "pro-layout-arrow "
|
|
66
169
|
})
|
|
@@ -75,45 +75,43 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
75
75
|
confirm?: boolean | import("antd").ModalFuncProps | import("../../../render/propsType").FunctionArgs<any, boolean | import("antd").ModalFuncProps>;
|
|
76
76
|
show?: boolean | ReactiveFunction<any, boolean>;
|
|
77
77
|
component?: React.ReactNode | ReactiveFunction<any, React.ReactNode>;
|
|
78
|
-
style?: React.CSSProperties;
|
|
79
78
|
id?: string;
|
|
80
|
-
children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
|
|
81
|
-
trim?: boolean;
|
|
82
|
-
normalize?: (value: any, prevValue: any, allValues: import("@rc-component/form/lib/interface").Store) => any;
|
|
83
79
|
className?: string;
|
|
84
|
-
vertical?: boolean;
|
|
85
80
|
hidden?: boolean;
|
|
81
|
+
style?: React.CSSProperties;
|
|
82
|
+
children?: React.ReactNode | ((form: FormInstance<any>) => React.ReactNode);
|
|
86
83
|
onReset?: () => void;
|
|
87
84
|
prefixCls?: string;
|
|
85
|
+
status?: "" | "warning" | "error" | "success" | "validating";
|
|
88
86
|
rootClassName?: string;
|
|
89
|
-
status?: "" | "success" | "error" | "warning" | "validating";
|
|
90
|
-
trigger?: string;
|
|
91
|
-
colon?: boolean;
|
|
92
87
|
isView?: boolean;
|
|
93
|
-
|
|
94
|
-
getValueProps?: ((value: any) => Record<string, unknown>) & ((value: any) => Record<string, unknown>);
|
|
95
|
-
layout?: import("antd/es/form/Form").FormItemLayout;
|
|
96
|
-
help?: React.ReactNode;
|
|
97
|
-
preserve?: boolean;
|
|
88
|
+
colon?: boolean;
|
|
98
89
|
htmlFor?: string;
|
|
99
90
|
labelAlign?: import("antd/es/form/interface").FormLabelAlign;
|
|
100
91
|
labelCol?: import("antd").ColProps;
|
|
92
|
+
vertical?: boolean;
|
|
101
93
|
getValueFromEvent?: (...args: import("@rc-component/form/lib/interface").EventArgs) => any;
|
|
94
|
+
normalize?: (value: any, prevValue: any, allValues: import("@rc-component/form/lib/interface").Store) => any;
|
|
102
95
|
shouldUpdate?: import("@rc-component/form/lib/Field").ShouldUpdate<any>;
|
|
96
|
+
trigger?: string;
|
|
103
97
|
validateTrigger?: string | false | string[];
|
|
104
98
|
validateDebounce?: number;
|
|
105
99
|
valuePropName?: string;
|
|
100
|
+
getValueProps?: ((value: any) => Record<string, unknown>) & ((value: any) => Record<string, unknown>);
|
|
106
101
|
messageVariables?: Record<string, string>;
|
|
107
102
|
initialValue?: any;
|
|
108
103
|
onMetaChange?: (meta: import("@rc-component/form/lib/Field").MetaEvent) => void;
|
|
104
|
+
preserve?: boolean;
|
|
109
105
|
isListField?: boolean;
|
|
110
106
|
isList?: boolean;
|
|
111
107
|
noStyle?: boolean;
|
|
112
108
|
hasFeedback?: boolean | {
|
|
113
109
|
icons: import("antd/es/form/FormItem").FeedbackIcons;
|
|
114
110
|
};
|
|
115
|
-
validateStatus?: "" | "
|
|
111
|
+
validateStatus?: "" | "warning" | "error" | "success" | "validating";
|
|
112
|
+
layout?: import("antd/es/form/Form").FormItemLayout;
|
|
116
113
|
wrapperCol?: import("antd").ColProps;
|
|
114
|
+
help?: React.ReactNode;
|
|
117
115
|
fieldId?: string;
|
|
118
116
|
valueType?: import("../../../render/propsType").ProFormValueType;
|
|
119
117
|
switchValue?: [any, any];
|
|
@@ -123,10 +121,12 @@ export declare const useFormItemProps: (column: FlexibleGroupColumnType, context
|
|
|
123
121
|
index?: number;
|
|
124
122
|
}) => string | React.ReactElement<any, any>;
|
|
125
123
|
viewType?: import("../../../render/propsType").ViewType;
|
|
124
|
+
trim?: boolean;
|
|
126
125
|
upperCase?: boolean;
|
|
127
126
|
toISOString?: boolean;
|
|
128
127
|
toCSTString?: boolean;
|
|
129
128
|
clearNotShow?: boolean;
|
|
129
|
+
desensitization?: [number, number] | ReactiveFunction<any, [number, number]>;
|
|
130
130
|
name: any;
|
|
131
131
|
dependencies: any[];
|
|
132
132
|
tooltip: string | {
|
|
@@ -29,7 +29,9 @@ var OpenMenu = props => {
|
|
|
29
29
|
var className = props.className,
|
|
30
30
|
dataSource = props.dataSource,
|
|
31
31
|
style = props.style,
|
|
32
|
-
onMenuClick = props.onMenuClick
|
|
32
|
+
onMenuClick = props.onMenuClick,
|
|
33
|
+
_props$textVisible = props.textVisible,
|
|
34
|
+
textVisible = _props$textVisible === void 0 ? true : _props$textVisible;
|
|
33
35
|
var _ref = dataSource || {},
|
|
34
36
|
menus = _ref.menus,
|
|
35
37
|
sideMenu = _ref.sideMenu;
|
|
@@ -53,6 +55,7 @@ var OpenMenu = props => {
|
|
|
53
55
|
var layoutTarget = layoutContext === null || layoutContext === void 0 ? void 0 : layoutContext.target;
|
|
54
56
|
var cls = (0, _classnames.default)({
|
|
55
57
|
'pro-layout-open-menu': true,
|
|
58
|
+
'pro-layout-menu-text-hidden': textVisible === false,
|
|
56
59
|
[`${className}`]: className
|
|
57
60
|
});
|
|
58
61
|
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
@import '../../../../../../style/variables.less';
|
|
2
2
|
|
|
3
3
|
.pro-layout-open-menu {
|
|
4
|
+
// 展开动画期间(Menu 传入 textVisible=false)隐藏文字,避免”挤压式逐字出现”;宽度过渡结束后再淡入
|
|
5
|
+
&.pro-layout-menu-text-hidden {
|
|
6
|
+
.@{ant-prefix}-menu-title-content {
|
|
7
|
+
div {
|
|
8
|
+
h2 {
|
|
9
|
+
opacity: 0 !important;
|
|
10
|
+
transition: none !important; // 确保隐藏时无过渡动画
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
4
15
|
|
|
5
16
|
.@{ant-prefix}-menu-root {
|
|
6
17
|
overflow-y: auto !important;
|
|
@@ -98,7 +109,8 @@
|
|
|
98
109
|
font-weight: 400;
|
|
99
110
|
font-size: var(--zaui-font-size-md, 14px);
|
|
100
111
|
opacity: 1;
|
|
101
|
-
|
|
112
|
+
// 修改:添加 150ms 的 opacity 淡入动画,消除"突然出现"的卡顿感
|
|
113
|
+
transition: opacity 0.15s ease-out, margin 0.3s, color 0.3s;
|
|
102
114
|
}
|
|
103
115
|
}
|
|
104
116
|
}
|
|
@@ -78,9 +78,24 @@
|
|
|
78
78
|
overflow-x: hidden;
|
|
79
79
|
overflow-y: auto;
|
|
80
80
|
|
|
81
|
+
// 与展开态一致:hover 使用透明背景 + 左侧品牌色半透明条
|
|
81
82
|
.@{ant-prefix}-menu-submenu-title:hover,
|
|
82
83
|
.@{ant-prefix}-menu-item:hover {
|
|
83
|
-
|
|
84
|
+
position: relative;
|
|
85
|
+
background-color: transparent !important;
|
|
86
|
+
|
|
87
|
+
&::before {
|
|
88
|
+
position: absolute;
|
|
89
|
+
left: var(--zaui-space-size-sm, 8px);
|
|
90
|
+
right: var(--zaui-space-size-sm, 8px);
|
|
91
|
+
width: auto;
|
|
92
|
+
min-height: 38px;
|
|
93
|
+
height: 80%;
|
|
94
|
+
background-color: var(--zaui-brand, #006aff);
|
|
95
|
+
border-radius: var(--zaui-border-radius, 8px);
|
|
96
|
+
opacity: 0.08;
|
|
97
|
+
content: '';
|
|
98
|
+
}
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
.@{ant-prefix}-menu-item {
|
|
@@ -4,13 +4,26 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
7
8
|
var _classnames = _interopRequireDefault(require("classnames"));
|
|
8
9
|
var _OpenMenu = _interopRequireDefault(require("./OpenMenu"));
|
|
9
10
|
var _FoldMenu = _interopRequireDefault(require("./FoldMenu"));
|
|
10
11
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
14
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
15
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
16
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
17
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
18
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // 折叠后菜单
|
|
19
|
+
// 菜单宽度配置
|
|
20
|
+
var MENU_CONFIG = {
|
|
21
|
+
TRANSITION_DURATION: 300,
|
|
22
|
+
// 宽度过渡时长(ms)
|
|
23
|
+
TEXT_VISIBLE_THRESHOLD: 150,
|
|
24
|
+
// 文字显示阈值(px, 约68%展开)
|
|
25
|
+
FULL_WIDTH: 219 // 完全展开宽度(px)
|
|
26
|
+
};
|
|
14
27
|
var Menu = props => {
|
|
15
28
|
var _ref = props || {},
|
|
16
29
|
headerHeight = _ref.headerHeight,
|
|
@@ -24,6 +37,83 @@ var Menu = props => {
|
|
|
24
37
|
sideMenuHeaderRender = _ref.sideMenuHeaderRender,
|
|
25
38
|
onMenuClick = _ref.onMenuClick;
|
|
26
39
|
var menus = [];
|
|
40
|
+
var menuRef = (0, _react.useRef)(null);
|
|
41
|
+
// 整合所有动画相关的refs
|
|
42
|
+
var animationStateRef = (0, _react.useRef)({
|
|
43
|
+
timer: null,
|
|
44
|
+
observer: null,
|
|
45
|
+
hasTriggered: false
|
|
46
|
+
});
|
|
47
|
+
var _useState = (0, _react.useState)(false),
|
|
48
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
49
|
+
isOpenMenuTextVisible = _useState2[0],
|
|
50
|
+
setIsOpenMenuTextVisible = _useState2[1];
|
|
51
|
+
|
|
52
|
+
// 提取清理逻辑
|
|
53
|
+
var cleanupAnimation = (0, _react.useCallback)(() => {
|
|
54
|
+
var state = animationStateRef.current;
|
|
55
|
+
if (state.timer) {
|
|
56
|
+
clearTimeout(state.timer);
|
|
57
|
+
state.timer = null;
|
|
58
|
+
}
|
|
59
|
+
if (state.observer) {
|
|
60
|
+
try {
|
|
61
|
+
state.observer.disconnect();
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.warn('ResizeObserver disconnect failed:', e);
|
|
64
|
+
}
|
|
65
|
+
state.observer = null;
|
|
66
|
+
}
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
// 触发文字显示
|
|
70
|
+
var showMenuText = (0, _react.useCallback)(() => {
|
|
71
|
+
var state = animationStateRef.current;
|
|
72
|
+
if (state.hasTriggered) return;
|
|
73
|
+
state.hasTriggered = true;
|
|
74
|
+
setIsOpenMenuTextVisible(true);
|
|
75
|
+
// 延迟清理,避免回调内竞态
|
|
76
|
+
setTimeout(cleanupAnimation, 0);
|
|
77
|
+
}, [cleanupAnimation]);
|
|
78
|
+
|
|
79
|
+
// ResizeObserver 监听宽度变化,提前显示文字
|
|
80
|
+
(0, _react.useEffect)(() => {
|
|
81
|
+
var _menuRef$current$getB, _menuRef$current, _menuRef$current$getB2;
|
|
82
|
+
var state = animationStateRef.current;
|
|
83
|
+
state.hasTriggered = false;
|
|
84
|
+
|
|
85
|
+
// 折叠态:清理并隐藏文字
|
|
86
|
+
if (!collapsed) {
|
|
87
|
+
setIsOpenMenuTextVisible(false);
|
|
88
|
+
cleanupAnimation();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 检查是否已展开
|
|
93
|
+
var currentWidth = (_menuRef$current$getB = (_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 || (_menuRef$current$getB2 = _menuRef$current.getBoundingClientRect) === null || _menuRef$current$getB2 === void 0 ? void 0 : _menuRef$current$getB2.call(_menuRef$current).width) !== null && _menuRef$current$getB !== void 0 ? _menuRef$current$getB : 0;
|
|
94
|
+
if (currentWidth >= MENU_CONFIG.FULL_WIDTH) {
|
|
95
|
+
state.hasTriggered = true;
|
|
96
|
+
setIsOpenMenuTextVisible(true);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 创建 ResizeObserver
|
|
101
|
+
var supportsResizeObserver = typeof ResizeObserver !== 'undefined';
|
|
102
|
+
if (supportsResizeObserver && menuRef.current) {
|
|
103
|
+
state.observer = new ResizeObserver(entries => {
|
|
104
|
+
var _entries$0$contentRec, _entries$;
|
|
105
|
+
var width = (_entries$0$contentRec = (_entries$ = entries[0]) === null || _entries$ === void 0 ? void 0 : _entries$.contentRect.width) !== null && _entries$0$contentRec !== void 0 ? _entries$0$contentRec : 0;
|
|
106
|
+
if (width >= MENU_CONFIG.TEXT_VISIBLE_THRESHOLD) {
|
|
107
|
+
showMenuText();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
state.observer.observe(menuRef.current);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Fallback:定时器保底
|
|
114
|
+
state.timer = setTimeout(showMenuText, MENU_CONFIG.TRANSITION_DURATION);
|
|
115
|
+
return cleanupAnimation;
|
|
116
|
+
}, [collapsed, cleanupAnimation, showMenuText]);
|
|
27
117
|
var menuCls = (0, _classnames.default)({
|
|
28
118
|
'pro-layout-menu': true,
|
|
29
119
|
'pro-layout-menu-open': collapsed
|
|
@@ -37,10 +127,17 @@ var Menu = props => {
|
|
|
37
127
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {});
|
|
38
128
|
}
|
|
39
129
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
130
|
+
ref: menuRef,
|
|
40
131
|
className: menuCls,
|
|
41
132
|
style: {
|
|
42
133
|
top: notice ? 96 + headerHeight - 64 : headerHeight
|
|
43
134
|
},
|
|
135
|
+
onTransitionEnd: e => {
|
|
136
|
+
// Fallback:确保宽度过渡结束后文字一定显示
|
|
137
|
+
if (e.propertyName === 'width' && e.target === menuRef.current && collapsed) {
|
|
138
|
+
showMenuText();
|
|
139
|
+
}
|
|
140
|
+
},
|
|
44
141
|
children: [sideMenuHeaderRender, /*#__PURE__*/(0, _jsxRuntime.jsx)(_OpenMenu.default, {
|
|
45
142
|
dataSource: {
|
|
46
143
|
menus,
|
|
@@ -48,6 +145,7 @@ var Menu = props => {
|
|
|
48
145
|
height: headerHeight + (notice ? 32 : 0) + 48
|
|
49
146
|
},
|
|
50
147
|
onMenuClick: onMenuClick,
|
|
148
|
+
textVisible: isOpenMenuTextVisible,
|
|
51
149
|
style: {
|
|
52
150
|
display: collapsed ? 'block' : 'none'
|
|
53
151
|
}
|
|
@@ -67,7 +165,10 @@ var Menu = props => {
|
|
|
67
165
|
}
|
|
68
166
|
}), sideMenuFooterRender || /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
69
167
|
className: "pro-layout-menu-collapsed",
|
|
70
|
-
onClick:
|
|
168
|
+
onClick: () => {
|
|
169
|
+
setIsOpenMenuTextVisible(false);
|
|
170
|
+
onToggle === null || onToggle === void 0 || onToggle();
|
|
171
|
+
},
|
|
71
172
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
72
173
|
className: "pro-layout-arrow "
|
|
73
174
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zat-design/sisyphus-react",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"@dnd-kit/utilities": "^3.2.1",
|
|
93
93
|
"@rc-component/picker": "^1.9.0",
|
|
94
94
|
"@zat-design/utils": "4.0.0",
|
|
95
|
+
"@zat-design/sisyphus-login": "4.0.0-beta.1",
|
|
95
96
|
"ahooks": "3.9.5",
|
|
96
97
|
"antd": "^6.2.2",
|
|
97
98
|
"big.js": "^6.2.1",
|