@hi-ui/menu 4.3.2 → 5.0.0-alpha.0
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/CHANGELOG.md +77 -0
- package/lib/cjs/EnterIcon.js +44 -0
- package/lib/cjs/GroupMenu.js +96 -0
- package/lib/cjs/Menu.js +22 -10
- package/lib/cjs/MenuItem.js +4 -3
- package/lib/cjs/MenuSearch.js +322 -0
- package/lib/cjs/SideMenu.js +139 -0
- package/lib/cjs/button/lib/esm/Button.js +109 -0
- package/lib/cjs/button/lib/esm/ButtonGroup.js +56 -0
- package/lib/cjs/button/lib/esm/styles/index.scss.js +35 -0
- package/lib/cjs/index.js +8 -0
- package/lib/cjs/styles/index.scss.js +1 -1
- package/lib/cjs/util.js +95 -1
- package/lib/esm/EnterIcon.js +32 -0
- package/lib/esm/GroupMenu.js +83 -0
- package/lib/esm/Menu.js +23 -11
- package/lib/esm/MenuItem.js +4 -3
- package/lib/esm/MenuSearch.js +305 -0
- package/lib/esm/SideMenu.js +124 -0
- package/lib/esm/button/lib/esm/Button.js +97 -0
- package/lib/esm/button/lib/esm/ButtonGroup.js +44 -0
- package/lib/esm/button/lib/esm/styles/index.scss.js +23 -0
- package/lib/esm/index.js +3 -0
- package/lib/esm/styles/index.scss.js +1 -1
- package/lib/esm/util.js +95 -2
- package/lib/types/EnterIcon.d.ts +1 -0
- package/lib/types/GroupMenu.d.ts +29 -0
- package/lib/types/Menu.d.ts +4 -0
- package/lib/types/MenuSearch.d.ts +37 -0
- package/lib/types/SideMenu.d.ts +58 -0
- package/lib/types/context.d.ts +2 -1
- package/lib/types/index.d.ts +3 -0
- package/lib/types/util.d.ts +16 -0
- package/package.json +27 -19
package/lib/cjs/util.js
CHANGED
|
@@ -13,7 +13,39 @@ Object.defineProperty(exports, '__esModule', {
|
|
|
13
13
|
value: true
|
|
14
14
|
});
|
|
15
15
|
var treeUtils = require('@hi-ui/tree-utils');
|
|
16
|
-
|
|
16
|
+
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
|
17
|
+
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
|
18
|
+
if (it) return (it = it.call(o)).next.bind(it);
|
|
19
|
+
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
|
|
20
|
+
if (it) o = it;
|
|
21
|
+
var i = 0;
|
|
22
|
+
return function () {
|
|
23
|
+
if (i >= o.length) return {
|
|
24
|
+
done: true
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
done: false,
|
|
28
|
+
value: o[i++]
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
33
|
+
}
|
|
34
|
+
function _unsupportedIterableToArray(o, minLen) {
|
|
35
|
+
if (!o) return;
|
|
36
|
+
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
|
|
37
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
38
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
39
|
+
if (n === "Map" || n === "Set") return Array.from(o);
|
|
40
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
|
|
41
|
+
}
|
|
42
|
+
function _arrayLikeToArray(arr, len) {
|
|
43
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
44
|
+
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
|
45
|
+
arr2[i] = arr[i];
|
|
46
|
+
}
|
|
47
|
+
return arr2;
|
|
48
|
+
}
|
|
17
49
|
// 寻找某一节点的父节点
|
|
18
50
|
var getParentId = function getParentId(id, data) {
|
|
19
51
|
var parentId = '';
|
|
@@ -90,8 +122,70 @@ var transformTreeData = function transformTreeData(data, fieldNames) {
|
|
|
90
122
|
};
|
|
91
123
|
return data.map(traverseTreeNode);
|
|
92
124
|
};
|
|
125
|
+
/**
|
|
126
|
+
* 增强版搜索函数,返回包含路径信息的结果
|
|
127
|
+
*/
|
|
128
|
+
function searchMenuWithPath(data, keyword) {
|
|
129
|
+
if (!keyword || !data || data.length === 0) {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
var results = [];
|
|
133
|
+
var processedIds = new Set();
|
|
134
|
+
function searchInTree(nodes, currentPath) {
|
|
135
|
+
if (currentPath === void 0) {
|
|
136
|
+
currentPath = [];
|
|
137
|
+
}
|
|
138
|
+
var _a;
|
|
139
|
+
for (var _iterator3 = _createForOfIteratorHelperLoose(nodes), _step3; !(_step3 = _iterator3()).done;) {
|
|
140
|
+
var node = _step3.value;
|
|
141
|
+
var nodePath = [].concat(currentPath, [node]);
|
|
142
|
+
var isMatched = (_a = node.title) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase().includes(keyword.toLowerCase());
|
|
143
|
+
if (isMatched) {
|
|
144
|
+
if (!node.children || node.children.length === 0) {
|
|
145
|
+
// 叶子节点
|
|
146
|
+
if (!processedIds.has(node.id)) {
|
|
147
|
+
results.push({
|
|
148
|
+
node: node,
|
|
149
|
+
path: nodePath,
|
|
150
|
+
level: nodePath.length - 1
|
|
151
|
+
});
|
|
152
|
+
processedIds.add(node.id);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
// 父节点,添加所有子节点
|
|
156
|
+
addAllDescendantsWithPath(node.children, nodePath);
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
// 继续搜索子节点
|
|
160
|
+
if (node.children && node.children.length > 0) {
|
|
161
|
+
searchInTree(node.children, nodePath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function addAllDescendantsWithPath(children, parentPath) {
|
|
167
|
+
for (var _iterator4 = _createForOfIteratorHelperLoose(children), _step4; !(_step4 = _iterator4()).done;) {
|
|
168
|
+
var child = _step4.value;
|
|
169
|
+
var childPath = [].concat(parentPath, [child]);
|
|
170
|
+
if (!processedIds.has(child.id)) {
|
|
171
|
+
results.push({
|
|
172
|
+
node: child,
|
|
173
|
+
path: childPath,
|
|
174
|
+
level: childPath.length - 1
|
|
175
|
+
});
|
|
176
|
+
processedIds.add(child.id);
|
|
177
|
+
}
|
|
178
|
+
if (child.children && child.children.length > 0) {
|
|
179
|
+
addAllDescendantsWithPath(child.children, childPath);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
searchInTree(data);
|
|
184
|
+
return results;
|
|
185
|
+
}
|
|
93
186
|
exports.filterTreeData = filterTreeData;
|
|
94
187
|
exports.getAncestorIds = getAncestorIds;
|
|
95
188
|
exports.getIdsWithChildren = getIdsWithChildren;
|
|
96
189
|
exports.getParentId = getParentId;
|
|
190
|
+
exports.searchMenuWithPath = searchMenuWithPath;
|
|
97
191
|
exports.transformTreeData = transformTreeData;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** @LICENSE
|
|
2
|
+
* @hi-ui/menu
|
|
3
|
+
* https://github.com/XiaoMi/hiui/tree/master/packages/ui/menu#readme
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) HiUI <mi-hiui@xiaomi.com>.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
var EnterIcon = function EnterIcon() {
|
|
12
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
13
|
+
width: "12",
|
|
14
|
+
height: "12",
|
|
15
|
+
viewBox: "0 0 12 12",
|
|
16
|
+
fill: "none",
|
|
17
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
18
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
19
|
+
d: "M4 9L2 7L4 5",
|
|
20
|
+
stroke: "#91959e",
|
|
21
|
+
strokeWidth: "1.2",
|
|
22
|
+
strokeLinecap: "round",
|
|
23
|
+
strokeLinejoin: "round"
|
|
24
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
25
|
+
d: "M10 3L10 6.25C10 6.66422 9.66423 7 9.25 7L2 7",
|
|
26
|
+
stroke: "#91959e",
|
|
27
|
+
strokeWidth: "1.2",
|
|
28
|
+
strokeLinecap: "round",
|
|
29
|
+
strokeLinejoin: "round"
|
|
30
|
+
}));
|
|
31
|
+
};
|
|
32
|
+
export { EnterIcon };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** @LICENSE
|
|
2
|
+
* @hi-ui/menu
|
|
3
|
+
* https://github.com/XiaoMi/hiui/tree/master/packages/ui/menu#readme
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) HiUI <mi-hiui@xiaomi.com>.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*/
|
|
10
|
+
import { __rest } from 'tslib';
|
|
11
|
+
import React, { forwardRef, useCallback } from 'react';
|
|
12
|
+
import { getPrefixCls, cx } from '@hi-ui/classname';
|
|
13
|
+
import { __DEV__ } from '@hi-ui/env';
|
|
14
|
+
import { isArrayNonEmpty } from '@hi-ui/type-assertion';
|
|
15
|
+
import { useLatestCallback } from '@hi-ui/use-latest';
|
|
16
|
+
import { useUncontrolledState } from '@hi-ui/use-uncontrolled-state';
|
|
17
|
+
import Scrollbar from '@hi-ui/scrollbar';
|
|
18
|
+
var _role = 'group-menu';
|
|
19
|
+
var GROUP_MENU_PREFIX = getPrefixCls(_role);
|
|
20
|
+
/**
|
|
21
|
+
* 分组菜单
|
|
22
|
+
*/
|
|
23
|
+
var GroupMenu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
24
|
+
var _a$prefixCls = _a.prefixCls,
|
|
25
|
+
prefixCls = _a$prefixCls === void 0 ? GROUP_MENU_PREFIX : _a$prefixCls,
|
|
26
|
+
_a$role = _a.role,
|
|
27
|
+
role = _a$role === void 0 ? _role : _a$role,
|
|
28
|
+
className = _a.className,
|
|
29
|
+
_a$data = _a.data,
|
|
30
|
+
data = _a$data === void 0 ? [] : _a$data,
|
|
31
|
+
onClick = _a.onClick,
|
|
32
|
+
_a$defaultActiveId = _a.defaultActiveId,
|
|
33
|
+
defaultActiveId = _a$defaultActiveId === void 0 ? '' : _a$defaultActiveId,
|
|
34
|
+
activeIdProp = _a.activeId,
|
|
35
|
+
titleRender = _a.titleRender,
|
|
36
|
+
rest = __rest(_a, ["prefixCls", "role", "className", "data", "onClick", "defaultActiveId", "activeId", "titleRender"]);
|
|
37
|
+
var _useUncontrolledState = useUncontrolledState(defaultActiveId, activeIdProp),
|
|
38
|
+
activeId = _useUncontrolledState[0],
|
|
39
|
+
tryChangeActiveId = _useUncontrolledState[1];
|
|
40
|
+
var handleClick = useLatestCallback(function (evt, id, item) {
|
|
41
|
+
tryChangeActiveId(id);
|
|
42
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(evt, id, item);
|
|
43
|
+
});
|
|
44
|
+
var renderItem = useCallback(function (data) {
|
|
45
|
+
return data.map(function (item) {
|
|
46
|
+
var _cx;
|
|
47
|
+
var id = item.id,
|
|
48
|
+
icon = item.icon,
|
|
49
|
+
title = item.title,
|
|
50
|
+
_item$children = item.children,
|
|
51
|
+
children = _item$children === void 0 ? [] : _item$children,
|
|
52
|
+
disabled = item.disabled;
|
|
53
|
+
var isParent = isArrayNonEmpty(children);
|
|
54
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
55
|
+
key: id,
|
|
56
|
+
className: cx(isParent ? prefixCls + "-parent-item" : prefixCls + "-item", (_cx = {}, _cx[prefixCls + "-item--active"] = activeId === id, _cx[prefixCls + "-item--disabled"] = disabled, _cx[prefixCls + "-item--empty"] = !title && !icon, _cx)),
|
|
57
|
+
onClick: function onClick(evt) {
|
|
58
|
+
if (disabled || isParent) return;
|
|
59
|
+
evt.stopPropagation();
|
|
60
|
+
handleClick(evt, id, item);
|
|
61
|
+
}
|
|
62
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
63
|
+
className: cx(prefixCls + "-item__content")
|
|
64
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
65
|
+
className: cx(prefixCls + "-item__icon")
|
|
66
|
+
}, icon), /*#__PURE__*/React.createElement("div", {
|
|
67
|
+
className: cx(prefixCls + "-item__title")
|
|
68
|
+
}, typeof titleRender === 'function' ? titleRender(item) : title)), isParent && renderItem(children));
|
|
69
|
+
});
|
|
70
|
+
}, [activeId, handleClick, prefixCls, titleRender]);
|
|
71
|
+
return /*#__PURE__*/React.createElement("div", Object.assign({
|
|
72
|
+
className: cx("" + prefixCls, className),
|
|
73
|
+
ref: ref,
|
|
74
|
+
role: role
|
|
75
|
+
}, rest), /*#__PURE__*/React.createElement(Scrollbar, {
|
|
76
|
+
onlyScrollVisible: true,
|
|
77
|
+
axes: "y"
|
|
78
|
+
}, renderItem(data)));
|
|
79
|
+
});
|
|
80
|
+
if (__DEV__) {
|
|
81
|
+
GroupMenu.displayName = 'GroupMenu';
|
|
82
|
+
}
|
|
83
|
+
export { GroupMenu };
|
package/lib/esm/Menu.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* LICENSE file in the root directory of this source tree.
|
|
9
9
|
*/
|
|
10
10
|
import { __rest } from 'tslib';
|
|
11
|
-
import React, { forwardRef, useState, useMemo, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
11
|
+
import React, { forwardRef, useState, useMemo, useEffect, useRef, useCallback, useLayoutEffect } from 'react';
|
|
12
12
|
import { getPrefixCls, cx } from '@hi-ui/classname';
|
|
13
13
|
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@hi-ui/icons';
|
|
14
14
|
import { __DEV__ } from '@hi-ui/env';
|
|
@@ -70,7 +70,9 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
70
70
|
onClick = _a.onClick,
|
|
71
71
|
_a$size = _a.size,
|
|
72
72
|
size = _a$size === void 0 ? 'lg' : _a$size,
|
|
73
|
-
|
|
73
|
+
_a$showTitleOnMini = _a.showTitleOnMini,
|
|
74
|
+
showTitleOnMini = _a$showTitleOnMini === void 0 ? false : _a$showTitleOnMini,
|
|
75
|
+
rest = __rest(_a, ["prefixCls", "role", "className", "data", "fieldNames", "placement", "showCollapse", "expandedType", "showAllSubMenus", "defaultExpandAll", "defaultExpandedIds", "expandedIds", "onExpand", "defaultActiveId", "activeId", "onClickSubMenu", "collapsed", "defaultCollapsed", "overlayClassName", "onCollapse", "footerRender", "render", "extraHeader", "onClick", "size", "showTitleOnMini"]);
|
|
74
76
|
var i18n = useLocaleContext();
|
|
75
77
|
var _useUncontrolledState = useUncontrolledState(defaultActiveId, activeIdProp, onClick),
|
|
76
78
|
activeId = _useUncontrolledState[0],
|
|
@@ -93,6 +95,7 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
93
95
|
}, expandedIdsProp, onExpand),
|
|
94
96
|
expandedIds = _useUncontrolledState2[0],
|
|
95
97
|
updateExpandedIds = _useUncontrolledState2[1];
|
|
98
|
+
var expandedIdsRef = useRef(expandedIds);
|
|
96
99
|
var clickMenu = useCallback(function (id, raw) {
|
|
97
100
|
updateActiveId(id, raw);
|
|
98
101
|
}, [updateActiveId]);
|
|
@@ -101,14 +104,17 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
101
104
|
return expandedId !== id;
|
|
102
105
|
}) : expandedIds.concat(id);
|
|
103
106
|
updateExpandedIds(nextExpandedIds);
|
|
107
|
+
expandedIdsRef.current = nextExpandedIds;
|
|
104
108
|
if (onClickSubMenu) {
|
|
105
109
|
onClickSubMenu(id, nextExpandedIds);
|
|
106
110
|
}
|
|
107
111
|
}, [onClickSubMenu, expandedIds, updateExpandedIds]);
|
|
108
112
|
var closePopper = useCallback(function (id) {
|
|
109
|
-
|
|
113
|
+
var nextExpandedIds = expandedIds.filter(function (expandedId) {
|
|
110
114
|
return expandedId !== id;
|
|
111
|
-
})
|
|
115
|
+
});
|
|
116
|
+
updateExpandedIds(nextExpandedIds);
|
|
117
|
+
expandedIdsRef.current = nextExpandedIds;
|
|
112
118
|
}, [expandedIds, updateExpandedIds]);
|
|
113
119
|
var closeAllPopper = useCallback(function () {
|
|
114
120
|
updateExpandedIds([]);
|
|
@@ -141,6 +147,13 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
141
147
|
setContainerWidth(width);
|
|
142
148
|
}
|
|
143
149
|
});
|
|
150
|
+
useEffect(function () {
|
|
151
|
+
if (mini) {
|
|
152
|
+
updateExpandedIds([]);
|
|
153
|
+
} else {
|
|
154
|
+
updateExpandedIds(expandedIdsRef.current);
|
|
155
|
+
}
|
|
156
|
+
}, [mini, updateExpandedIds]);
|
|
144
157
|
var _useState4 = useState(0),
|
|
145
158
|
tagMaxCount = _useState4[0],
|
|
146
159
|
setTagMaxCount = _useState4[1];
|
|
@@ -155,7 +168,7 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
155
168
|
}, [transformedData, tagMaxCount]);
|
|
156
169
|
var getTagWidth = useCallback(function (index) {
|
|
157
170
|
if (!containerElement) return MIN_WIDTH;
|
|
158
|
-
var elements = containerElement.getElementsByClassName('hi-
|
|
171
|
+
var elements = containerElement.getElementsByClassName('hi-v5-menu-item');
|
|
159
172
|
var element = elements && elements[index];
|
|
160
173
|
if (!element) return MIN_WIDTH;
|
|
161
174
|
return element.getBoundingClientRect().width;
|
|
@@ -191,9 +204,7 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
191
204
|
var collapseNode = canToggle ? ( /*#__PURE__*/React.createElement("div", {
|
|
192
205
|
className: cx(prefixCls + "__toggle"),
|
|
193
206
|
onClick: function onClick() {
|
|
194
|
-
miniToggleAction.not();
|
|
195
|
-
// 关闭所有展开的子菜单,防止切换到 mini 模式后,子菜单还是展开的
|
|
196
|
-
updateExpandedIds([]);
|
|
207
|
+
return miniToggleAction.not();
|
|
197
208
|
}
|
|
198
209
|
}, mini ? /*#__PURE__*/React.createElement(MenuUnfoldOutlined, null) : /*#__PURE__*/React.createElement(MenuFoldOutlined, null))) : null;
|
|
199
210
|
return /*#__PURE__*/React.createElement(React.Fragment, null, isFunction(footerRender) ? footerRender({
|
|
@@ -203,12 +214,12 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
203
214
|
};
|
|
204
215
|
var renderItem = useCallback(function (menuItem, level) {
|
|
205
216
|
// 显示缩略内容
|
|
206
|
-
if (showMini && level === 1) {
|
|
217
|
+
if (showMini && level === 1 && !showTitleOnMini) {
|
|
207
218
|
return renderMenuItemMini(menuItem);
|
|
208
219
|
}
|
|
209
220
|
return isFunction(render) ? render(menuItem, level) : menuItem.title;
|
|
210
|
-
}, [render, showMini]);
|
|
211
|
-
var cls = cx(prefixCls, className, prefixCls + "--" + placement, prefixCls + "--size-" + size, mini && prefixCls + "--mini", (expandedType === 'pop' || showAllSubMenus || mini) && prefixCls + "--popup");
|
|
221
|
+
}, [render, showMini, showTitleOnMini]);
|
|
222
|
+
var cls = cx(prefixCls, className, prefixCls + "--" + placement, prefixCls + "--size-" + size, mini && prefixCls + "--mini", showTitleOnMini && prefixCls + "--show-title-on-mini", (expandedType === 'pop' || showAllSubMenus || mini) && prefixCls + "--popup");
|
|
212
223
|
return /*#__PURE__*/React.createElement("div", Object.assign({
|
|
213
224
|
ref: useMergeRefs(ref, setContainerElement),
|
|
214
225
|
role: role,
|
|
@@ -219,6 +230,7 @@ var Menu = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
|
219
230
|
expandedType: expandedType,
|
|
220
231
|
showAllSubMenus: showAllSubMenus,
|
|
221
232
|
mini: mini,
|
|
233
|
+
showTitleOnMini: showTitleOnMini,
|
|
222
234
|
clickMenu: clickMenu,
|
|
223
235
|
clickSubMenu: clickSubMenu,
|
|
224
236
|
closePopper: closePopper,
|
package/lib/esm/MenuItem.js
CHANGED
|
@@ -56,7 +56,8 @@ var MenuItem = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
56
56
|
clickSubMenu = _useContext.clickSubMenu,
|
|
57
57
|
closeAllPopper = _useContext.closeAllPopper,
|
|
58
58
|
activeParents = _useContext.activeParents,
|
|
59
|
-
overlayClassName = _useContext.overlayClassName
|
|
59
|
+
overlayClassName = _useContext.overlayClassName,
|
|
60
|
+
showTitleOnMini = _useContext.showTitleOnMini;
|
|
60
61
|
var _parentIds = (parentIds || []).concat(id);
|
|
61
62
|
var hasChildren = isArrayNonEmpty(children);
|
|
62
63
|
var mergedRef = useMergeRefs(itemRef, ref);
|
|
@@ -122,7 +123,7 @@ var MenuItem = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
122
123
|
visible: !!(expandedIds === null || expandedIds === void 0 ? void 0 : expandedIds.includes(id)),
|
|
123
124
|
attachEl: itemRef.current,
|
|
124
125
|
placement: 'right-start',
|
|
125
|
-
gutterGap: 16,
|
|
126
|
+
gutterGap: showTitleOnMini ? 8 : 16,
|
|
126
127
|
className: overlayClassName,
|
|
127
128
|
onClose: function onClose() {
|
|
128
129
|
closePopper === null || closePopper === void 0 ? void 0 : closePopper(id);
|
|
@@ -142,7 +143,7 @@ var MenuItem = /*#__PURE__*/forwardRef(function (_ref, ref) {
|
|
|
142
143
|
visible: !!(expandedIds === null || expandedIds === void 0 ? void 0 : expandedIds.includes(id)),
|
|
143
144
|
attachEl: itemRef.current,
|
|
144
145
|
placement: 'right-start',
|
|
145
|
-
gutterGap: 16,
|
|
146
|
+
gutterGap: showTitleOnMini ? 12 : 16,
|
|
146
147
|
disabledPortal: true,
|
|
147
148
|
className: overlayClassName,
|
|
148
149
|
onClose: function onClose() {
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/** @LICENSE
|
|
2
|
+
* @hi-ui/menu
|
|
3
|
+
* https://github.com/XiaoMi/hiui/tree/master/packages/ui/menu#readme
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) HiUI <mi-hiui@xiaomi.com>.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE file in the root directory of this source tree.
|
|
9
|
+
*/
|
|
10
|
+
import { __rest } from 'tslib';
|
|
11
|
+
import React, { forwardRef, useState, useRef, useLayoutEffect, useCallback, useEffect, useImperativeHandle } from 'react';
|
|
12
|
+
import { useLocaleContext } from '@hi-ui/core';
|
|
13
|
+
import { __DEV__ } from '@hi-ui/env';
|
|
14
|
+
import { getPrefixCls, cx } from '@hi-ui/classname';
|
|
15
|
+
import { ArrowUpOutlined, ArrowDownOutlined, SearchOutlined, CloseOutlined } from '@hi-ui/icons';
|
|
16
|
+
import IconButton from '@hi-ui/icon-button';
|
|
17
|
+
import './button/lib/esm/styles/index.scss.js';
|
|
18
|
+
import { Button } from './button/lib/esm/Button.js';
|
|
19
|
+
import './button/lib/esm/ButtonGroup.js';
|
|
20
|
+
import Input from '@hi-ui/input';
|
|
21
|
+
import Highlighter from '@hi-ui/highlighter';
|
|
22
|
+
import { useUncontrolledState } from '@hi-ui/use-uncontrolled-state';
|
|
23
|
+
import { useUncontrolledToggle } from '@hi-ui/use-toggle';
|
|
24
|
+
import EllipsisTooltip from '@hi-ui/ellipsis-tooltip';
|
|
25
|
+
import { EnterIcon } from './EnterIcon.js';
|
|
26
|
+
import { searchMenuWithPath } from './util.js';
|
|
27
|
+
var _role = 'menu-search';
|
|
28
|
+
var _prefix = getPrefixCls(_role);
|
|
29
|
+
var MenuSearch = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
30
|
+
var _cx, _cx2;
|
|
31
|
+
var _b, _c;
|
|
32
|
+
var innerRef = _a.innerRef,
|
|
33
|
+
_a$prefixCls = _a.prefixCls,
|
|
34
|
+
prefixCls = _a$prefixCls === void 0 ? _prefix : _a$prefixCls,
|
|
35
|
+
className = _a.className,
|
|
36
|
+
placeholder = _a.placeholder,
|
|
37
|
+
width = _a.width,
|
|
38
|
+
style = _a.style,
|
|
39
|
+
visibleProp = _a.visible,
|
|
40
|
+
data = _a.data,
|
|
41
|
+
_a$defaultValue = _a.defaultValue,
|
|
42
|
+
defaultValue = _a$defaultValue === void 0 ? '' : _a$defaultValue,
|
|
43
|
+
valueProp = _a.value,
|
|
44
|
+
onChange = _a.onChange,
|
|
45
|
+
onSelect = _a.onSelect,
|
|
46
|
+
onClear = _a.onClear,
|
|
47
|
+
onClose = _a.onClose,
|
|
48
|
+
onEsc = _a.onEsc;
|
|
49
|
+
__rest(_a, ["innerRef", "prefixCls", "className", "clearText", "placeholder", "notFoundContent", "width", "style", "visible", "data", "defaultValue", "value", "onChange", "onSearch", "onSelect", "onClear", "onClose", "onEsc"]);
|
|
50
|
+
var i18n = useLocaleContext();
|
|
51
|
+
var _useUncontrolledToggl = useUncontrolledToggle({
|
|
52
|
+
visible: visibleProp
|
|
53
|
+
}),
|
|
54
|
+
visible = _useUncontrolledToggl[0],
|
|
55
|
+
visibleAction = _useUncontrolledToggl[1];
|
|
56
|
+
var _useUncontrolledState = useUncontrolledState(defaultValue, valueProp, onChange),
|
|
57
|
+
value = _useUncontrolledState[0],
|
|
58
|
+
tryChangeValue = _useUncontrolledState[1];
|
|
59
|
+
var _useState = useState(-1),
|
|
60
|
+
currentIndex = _useState[0],
|
|
61
|
+
setCurrentIndex = _useState[1];
|
|
62
|
+
var listRef = useRef(null);
|
|
63
|
+
useLayoutEffect(function () {
|
|
64
|
+
if (currentIndex === -1 || !listRef.current) return;
|
|
65
|
+
var listContainer = listRef.current;
|
|
66
|
+
var selectedItem = listContainer.children[currentIndex];
|
|
67
|
+
if (!selectedItem) return;
|
|
68
|
+
var containerScrollTop = listContainer.scrollTop;
|
|
69
|
+
var containerHeight = listContainer.clientHeight;
|
|
70
|
+
var itemTop = selectedItem.offsetTop;
|
|
71
|
+
var itemHeight = selectedItem.offsetHeight;
|
|
72
|
+
// 计算元素的可见范围
|
|
73
|
+
var itemBottom = itemTop + itemHeight;
|
|
74
|
+
var visibleTop = containerScrollTop;
|
|
75
|
+
var visibleBottom = containerScrollTop + containerHeight;
|
|
76
|
+
// 判断是否需要滚动
|
|
77
|
+
var isItemAboveViewport = itemTop < visibleTop;
|
|
78
|
+
var isItemBelowViewport = itemBottom > visibleBottom;
|
|
79
|
+
if (isItemAboveViewport) {
|
|
80
|
+
// 如果元素在可视区域上方,滚动到元素顶部
|
|
81
|
+
listContainer.scrollTop = itemTop;
|
|
82
|
+
} else if (isItemBelowViewport) {
|
|
83
|
+
// 如果元素在可视区域下方,滚动到元素底部刚好可见
|
|
84
|
+
listContainer.scrollTop = itemBottom - containerHeight;
|
|
85
|
+
}
|
|
86
|
+
}, [currentIndex]);
|
|
87
|
+
var resultMemo = React.useMemo(function () {
|
|
88
|
+
if (!data || !value) return [];
|
|
89
|
+
// 使用新的搜索算法
|
|
90
|
+
var searchResults = searchMenuWithPath(data, value);
|
|
91
|
+
return searchResults.map(function (result) {
|
|
92
|
+
return Object.assign(Object.assign({}, result.node), {
|
|
93
|
+
level: result.level,
|
|
94
|
+
path: result.path,
|
|
95
|
+
// 添加路径信息用于显示
|
|
96
|
+
pathTitles: result.path.map(function (p) {
|
|
97
|
+
var _a;
|
|
98
|
+
return (_a = p.title) === null || _a === void 0 ? void 0 : _a.toString();
|
|
99
|
+
}).filter(Boolean)
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}, [data, value]);
|
|
103
|
+
var handleChange = useCallback(function (value) {
|
|
104
|
+
tryChangeValue(value);
|
|
105
|
+
}, [tryChangeValue]);
|
|
106
|
+
var handleSelect = useCallback(function (id, item, index) {
|
|
107
|
+
var _a;
|
|
108
|
+
setCurrentIndex(index);
|
|
109
|
+
visibleAction.off();
|
|
110
|
+
// 让列表容器获取焦点,确保键盘导航可用
|
|
111
|
+
(_a = listRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
112
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(id, item);
|
|
113
|
+
}, [onSelect, visibleAction]);
|
|
114
|
+
var handleMove = useCallback(function (direction) {
|
|
115
|
+
if (!resultMemo) return;
|
|
116
|
+
setCurrentIndex(function (prev) {
|
|
117
|
+
if (direction === 'up') {
|
|
118
|
+
return prev - 1 < 0 ? (resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) - 1 : prev - 1;
|
|
119
|
+
} else {
|
|
120
|
+
return prev + 1 > (resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) - 1 ? 0 : prev + 1;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}, [resultMemo]);
|
|
124
|
+
var handleEnter = useCallback(function () {
|
|
125
|
+
if (!resultMemo) return;
|
|
126
|
+
if (currentIndex === -1) {
|
|
127
|
+
setCurrentIndex(0);
|
|
128
|
+
}
|
|
129
|
+
visibleAction.off();
|
|
130
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(resultMemo[currentIndex].id, resultMemo[currentIndex]);
|
|
131
|
+
}, [resultMemo, currentIndex, onSelect, visibleAction]);
|
|
132
|
+
var handleClear = useCallback(function () {
|
|
133
|
+
tryChangeValue('');
|
|
134
|
+
setCurrentIndex(-1);
|
|
135
|
+
onClear === null || onClear === void 0 ? void 0 : onClear();
|
|
136
|
+
}, [onClear, tryChangeValue]);
|
|
137
|
+
var handleClose = useCallback(function () {
|
|
138
|
+
visibleAction.off();
|
|
139
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
140
|
+
}, [onClose, visibleAction]);
|
|
141
|
+
var handleEscape = useCallback(function () {
|
|
142
|
+
handleClose();
|
|
143
|
+
onEsc === null || onEsc === void 0 ? void 0 : onEsc();
|
|
144
|
+
}, [handleClose, onEsc]);
|
|
145
|
+
var handleKeyDown = useCallback(function (e) {
|
|
146
|
+
if (e.key === 'ArrowUp') {
|
|
147
|
+
handleMove('up');
|
|
148
|
+
}
|
|
149
|
+
if (e.key === 'ArrowDown') {
|
|
150
|
+
handleMove('down');
|
|
151
|
+
}
|
|
152
|
+
if (e.key === 'Enter') {
|
|
153
|
+
handleEnter();
|
|
154
|
+
}
|
|
155
|
+
if (e.key === 'Escape') {
|
|
156
|
+
handleEscape();
|
|
157
|
+
}
|
|
158
|
+
}, [handleEnter, handleMove, handleEscape]);
|
|
159
|
+
var _useState2 = useState(null),
|
|
160
|
+
inputRef = _useState2[0],
|
|
161
|
+
setInputRef = _useState2[1];
|
|
162
|
+
useEffect(function () {
|
|
163
|
+
if (!value || !inputRef) {
|
|
164
|
+
visibleAction.off();
|
|
165
|
+
} else {
|
|
166
|
+
visibleAction.on();
|
|
167
|
+
}
|
|
168
|
+
}, [inputRef, value, visibleAction]);
|
|
169
|
+
useImperativeHandle(innerRef, function () {
|
|
170
|
+
return {
|
|
171
|
+
show: function show() {
|
|
172
|
+
visibleAction.on();
|
|
173
|
+
},
|
|
174
|
+
hide: function hide() {
|
|
175
|
+
visibleAction.off();
|
|
176
|
+
},
|
|
177
|
+
focus: function focus() {
|
|
178
|
+
inputRef === null || inputRef === void 0 ? void 0 : inputRef.focus();
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
var cls = cx(prefixCls, className, (_cx = {}, _cx[prefixCls + "--open"] = visible, _cx));
|
|
183
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
184
|
+
className: cls,
|
|
185
|
+
style: style
|
|
186
|
+
}, /*#__PURE__*/React.createElement(MenuSearchInput, {
|
|
187
|
+
width: width,
|
|
188
|
+
prefixCls: prefixCls,
|
|
189
|
+
placeholder: placeholder,
|
|
190
|
+
value: value,
|
|
191
|
+
onChange: handleChange,
|
|
192
|
+
onClear: handleClear,
|
|
193
|
+
onClose: handleClose,
|
|
194
|
+
onKeyDown: handleKeyDown,
|
|
195
|
+
inputRef: setInputRef
|
|
196
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
197
|
+
className: cx(prefixCls + "__content", (_cx2 = {}, _cx2[prefixCls + "__content--visible"] = visible, _cx2))
|
|
198
|
+
}, (resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) > 0 ? ( /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
199
|
+
className: prefixCls + "__header"
|
|
200
|
+
}, /*#__PURE__*/React.createElement(Highlighter, {
|
|
201
|
+
keyword: String((_b = resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) !== null && _b !== void 0 ? _b : 0)
|
|
202
|
+
}, i18n.get('menuSearch.searchResult', {
|
|
203
|
+
count: (_c = resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) !== null && _c !== void 0 ? _c : 0,
|
|
204
|
+
keyword: value
|
|
205
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
206
|
+
className: prefixCls + "__list",
|
|
207
|
+
ref: listRef,
|
|
208
|
+
tabIndex: -1,
|
|
209
|
+
onKeyDown: handleKeyDown
|
|
210
|
+
}, resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.map(function (item, index) {
|
|
211
|
+
var _cx3;
|
|
212
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
213
|
+
key: item.id,
|
|
214
|
+
className: cx(prefixCls + "__list-item", (_cx3 = {}, _cx3[prefixCls + "__list-item--selected"] = currentIndex === index, _cx3)),
|
|
215
|
+
onClick: function onClick() {
|
|
216
|
+
return handleSelect(item.id, item, index);
|
|
217
|
+
}
|
|
218
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
219
|
+
className: prefixCls + "__list-item__title"
|
|
220
|
+
}, /*#__PURE__*/React.createElement(EllipsisTooltip, {
|
|
221
|
+
tooltipProps: {
|
|
222
|
+
style: {
|
|
223
|
+
maxWidth: 320
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}, /*#__PURE__*/React.createElement(Highlighter, {
|
|
227
|
+
keyword: value
|
|
228
|
+
}, item.pathTitles.join('/')))));
|
|
229
|
+
})))) : ( /*#__PURE__*/React.createElement("div", {
|
|
230
|
+
className: prefixCls + "__empty"
|
|
231
|
+
}, /*#__PURE__*/React.createElement("div", null, i18n.menuSearch.searchEmptyResult)))), (resultMemo === null || resultMemo === void 0 ? void 0 : resultMemo.length) > 0 && ( /*#__PURE__*/React.createElement("div", {
|
|
232
|
+
className: prefixCls + "__footer"
|
|
233
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
234
|
+
className: prefixCls + "__footer-item"
|
|
235
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
236
|
+
className: prefixCls + "__footer-item__icon"
|
|
237
|
+
}, /*#__PURE__*/React.createElement(ArrowUpOutlined, null), /*#__PURE__*/React.createElement(ArrowDownOutlined, null)), /*#__PURE__*/React.createElement("span", {
|
|
238
|
+
className: prefixCls + "__footer-item__text"
|
|
239
|
+
}, i18n.menuSearch.moveCursor)), /*#__PURE__*/React.createElement("div", {
|
|
240
|
+
className: prefixCls + "__footer-item"
|
|
241
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
242
|
+
className: prefixCls + "__footer-item__icon"
|
|
243
|
+
}, /*#__PURE__*/React.createElement(EnterIcon, null)), /*#__PURE__*/React.createElement("span", {
|
|
244
|
+
className: prefixCls + "__footer-item__text"
|
|
245
|
+
}, i18n.menuSearch.confirmSelect)), /*#__PURE__*/React.createElement("div", {
|
|
246
|
+
className: prefixCls + "__footer-item"
|
|
247
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
248
|
+
className: prefixCls + "__footer-item__icon"
|
|
249
|
+
}, "esc"), /*#__PURE__*/React.createElement("span", {
|
|
250
|
+
className: prefixCls + "__footer-item__text"
|
|
251
|
+
}, i18n.menuSearch.hideWindow)))));
|
|
252
|
+
});
|
|
253
|
+
if (__DEV__) {
|
|
254
|
+
MenuSearch.displayName = 'MenuSearch';
|
|
255
|
+
}
|
|
256
|
+
var MenuSearchInput = /*#__PURE__*/forwardRef(function (_a, ref) {
|
|
257
|
+
var prefixCls = _a.prefixCls,
|
|
258
|
+
placeholder = _a.placeholder,
|
|
259
|
+
width = _a.width,
|
|
260
|
+
value = _a.value,
|
|
261
|
+
_onChange = _a.onChange,
|
|
262
|
+
onClear = _a.onClear,
|
|
263
|
+
onClose = _a.onClose,
|
|
264
|
+
onKeyDown = _a.onKeyDown,
|
|
265
|
+
inputRef = _a.inputRef,
|
|
266
|
+
rest = __rest(_a, ["prefixCls", "placeholder", "width", "value", "onChange", "onClear", "onClose", "onKeyDown", "inputRef"]);
|
|
267
|
+
var i18n = useLocaleContext();
|
|
268
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
269
|
+
ref: ref,
|
|
270
|
+
className: prefixCls + "__input-wrapper",
|
|
271
|
+
style: {
|
|
272
|
+
width: width
|
|
273
|
+
}
|
|
274
|
+
}, /*#__PURE__*/React.createElement(Input, Object.assign({
|
|
275
|
+
ref: inputRef,
|
|
276
|
+
className: prefixCls + "__input",
|
|
277
|
+
classNames: {
|
|
278
|
+
prefix: prefixCls + "__input-prefix"
|
|
279
|
+
},
|
|
280
|
+
appearance: "unset",
|
|
281
|
+
placeholder: placeholder,
|
|
282
|
+
prefix: /*#__PURE__*/React.createElement(SearchOutlined, null),
|
|
283
|
+
suffix: /*#__PURE__*/React.createElement(Button, {
|
|
284
|
+
className: prefixCls + "__input-clear",
|
|
285
|
+
appearance: "link",
|
|
286
|
+
size: "xs",
|
|
287
|
+
onClick: onClear
|
|
288
|
+
}, i18n.menuSearch.clear),
|
|
289
|
+
value: value,
|
|
290
|
+
onChange: function onChange(e) {
|
|
291
|
+
return _onChange === null || _onChange === void 0 ? void 0 : _onChange(e.target.value);
|
|
292
|
+
},
|
|
293
|
+
onKeyDown: onKeyDown
|
|
294
|
+
}, rest)), /*#__PURE__*/React.createElement("span", {
|
|
295
|
+
className: prefixCls + "__close"
|
|
296
|
+
}, /*#__PURE__*/React.createElement(IconButton, {
|
|
297
|
+
icon: /*#__PURE__*/React.createElement(CloseOutlined, null),
|
|
298
|
+
effect: true,
|
|
299
|
+
onClick: onClose
|
|
300
|
+
})));
|
|
301
|
+
});
|
|
302
|
+
if (__DEV__) {
|
|
303
|
+
MenuSearchInput.displayName = 'MenuSearchInput';
|
|
304
|
+
}
|
|
305
|
+
export { MenuSearch, MenuSearchInput };
|