@aloudata/aloudata-design 3.1.5 → 3.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConfigProvider/getUserList.d.ts +47 -0
- package/dist/ConfigProvider/getUserList.js.map +1 -1
- package/dist/ConfigProvider/hooks/useGetUserList.d.ts +7 -0
- package/dist/ConfigProvider/hooks/useGetUserList.js +5 -1
- package/dist/ConfigProvider/hooks/useGetUserList.js.map +1 -1
- package/dist/ConfigProvider/index.d.ts +5 -1
- package/dist/ConfigProvider/index.js +6 -2
- package/dist/ConfigProvider/index.js.map +1 -1
- package/dist/Dropdown/index.d.ts +7 -2
- package/dist/Dropdown/index.js +32 -23
- package/dist/Dropdown/index.js.map +1 -1
- package/dist/MemberPicker/components/MultipleOption.d.ts +1 -0
- package/dist/MemberPicker/components/MultipleOption.js +3 -1
- package/dist/MemberPicker/components/MultipleOption.js.map +1 -1
- package/dist/MemberPicker/components/NickLabel.d.ts +5 -0
- package/dist/MemberPicker/components/NickLabel.js +14 -4
- package/dist/MemberPicker/components/NickLabel.js.map +1 -1
- package/dist/MemberPicker/components/Panel.d.ts +4 -0
- package/dist/MemberPicker/components/Panel.js +13 -4
- package/dist/MemberPicker/components/Panel.js.map +1 -1
- package/dist/MemberPicker/components/PanelWrapper.js +25 -24
- package/dist/MemberPicker/components/PanelWrapper.js.map +1 -1
- package/dist/MemberPicker/components/SearchFeedback.d.ts +7 -0
- package/dist/MemberPicker/components/SearchFeedback.js +27 -0
- package/dist/MemberPicker/components/SearchFeedback.js.map +1 -0
- package/dist/MemberPicker/components/SingleOption.d.ts +1 -0
- package/dist/MemberPicker/components/SingleOption.js +3 -1
- package/dist/MemberPicker/components/SingleOption.js.map +1 -1
- package/dist/MemberPicker/components/UserGroupSelection.d.ts +4 -1
- package/dist/MemberPicker/components/UserGroupSelection.js +29 -22
- package/dist/MemberPicker/components/UserGroupSelection.js.map +1 -1
- package/dist/MemberPicker/dialog/DialogColumns.d.ts +5 -0
- package/dist/MemberPicker/dialog/DialogColumns.js +59 -0
- package/dist/MemberPicker/dialog/DialogColumns.js.map +1 -0
- package/dist/MemberPicker/dialog/DialogContent.d.ts +3 -0
- package/dist/MemberPicker/dialog/DialogContent.js +106 -0
- package/dist/MemberPicker/dialog/DialogContent.js.map +1 -0
- package/dist/MemberPicker/dialog/MemberOption.d.ts +16 -0
- package/dist/MemberPicker/dialog/MemberOption.js +101 -0
- package/dist/MemberPicker/dialog/MemberOption.js.map +1 -0
- package/dist/MemberPicker/dialog/MemberPickerDialog.d.ts +11 -0
- package/dist/MemberPicker/dialog/MemberPickerDialog.js +11 -0
- package/dist/MemberPicker/dialog/MemberPickerDialog.js.map +1 -0
- package/dist/MemberPicker/dialog/SelectedMemberPanel.d.ts +12 -0
- package/dist/MemberPicker/dialog/SelectedMemberPanel.js +37 -0
- package/dist/MemberPicker/dialog/SelectedMemberPanel.js.map +1 -0
- package/dist/MemberPicker/dialog/UserCandidatePanel.d.ts +13 -0
- package/dist/MemberPicker/dialog/UserCandidatePanel.js +168 -0
- package/dist/MemberPicker/dialog/UserCandidatePanel.js.map +1 -0
- package/dist/MemberPicker/dialog/UserGroupCandidatePanel.d.ts +13 -0
- package/dist/MemberPicker/dialog/UserGroupCandidatePanel.js +134 -0
- package/dist/MemberPicker/dialog/UserGroupCandidatePanel.js.map +1 -0
- package/dist/MemberPicker/dialog/helper.d.ts +20 -0
- package/dist/MemberPicker/dialog/helper.js +61 -0
- package/dist/MemberPicker/dialog/helper.js.map +1 -0
- package/dist/MemberPicker/dialog/types.d.ts +41 -0
- package/dist/MemberPicker/dialog/types.js +7 -0
- package/dist/MemberPicker/dialog/types.js.map +1 -0
- package/dist/MemberPicker/dialog/useDialogLocale.d.ts +103 -0
- package/dist/MemberPicker/dialog/useDialogLocale.js +12 -0
- package/dist/MemberPicker/dialog/useDialogLocale.js.map +1 -0
- package/dist/MemberPicker/dialog/useMemberPickerDraft.d.ts +27 -0
- package/dist/MemberPicker/dialog/useMemberPickerDraft.js +95 -0
- package/dist/MemberPicker/dialog/useMemberPickerDraft.js.map +1 -0
- package/dist/MemberPicker/dialog/useUserGroupCandidates.d.ts +29 -0
- package/dist/MemberPicker/dialog/useUserGroupCandidates.js +443 -0
- package/dist/MemberPicker/dialog/useUserGroupCandidates.js.map +1 -0
- package/dist/MemberPicker/index.d.ts +2 -0
- package/dist/MemberPicker/index.js +58 -34
- package/dist/MemberPicker/index.js.map +1 -1
- package/dist/MemberPicker/useMemberSearch.d.ts +8 -0
- package/dist/MemberPicker/useMemberSearch.js +51 -0
- package/dist/MemberPicker/useMemberSearch.js.map +1 -0
- package/dist/Menu/index.d.ts +2 -0
- package/dist/Menu/index.js +3 -2
- package/dist/Menu/index.js.map +1 -1
- package/dist/Modal/index.js +1 -1
- package/dist/Modal/index.js.map +1 -1
- package/dist/aloudata-design.css +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -2
- package/dist/locale/default.d.ts +29 -0
- package/dist/locale/en_US.d.ts +29 -0
- package/dist/locale/en_US.js +29 -0
- package/dist/locale/en_US.js.map +1 -1
- package/dist/locale/zh_CN.d.ts +29 -0
- package/dist/locale/zh_CN.js +29 -0
- package/dist/locale/zh_CN.js.map +1 -1
- package/package.json +2 -1
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
2
|
import Avatar from "../Avatar/index.js";
|
|
3
|
+
import DisabledContext from "../ConfigProvider/DisabledContext.js";
|
|
3
4
|
import { LocaleContext, getTranslator } from "../locale/default.js";
|
|
4
5
|
import { EUserType } from "../ConfigProvider/getUserList.js";
|
|
5
6
|
import AldCustomConfigProvider from "../ConfigProvider/index.js";
|
|
6
7
|
import Select_default from "../Select/index.js";
|
|
7
|
-
/* empty css */
|
|
8
|
-
import message from "../message/index.js";
|
|
9
8
|
import { EMemberPicker } from "./interface.js";
|
|
9
|
+
import SearchFeedback from "./components/SearchFeedback.js";
|
|
10
|
+
import MemberPickerDialog from "./dialog/MemberPickerDialog.js";
|
|
11
|
+
import useMemberSearch from "./useMemberSearch.js";
|
|
12
|
+
/* empty css */
|
|
10
13
|
import { getId } from "./utils/index.js";
|
|
11
14
|
import { isUser, isUserGroup } from "./utils/getUsersWithUserId.js";
|
|
12
15
|
import Panel from "./components/Panel.js";
|
|
@@ -14,7 +17,7 @@ import PanelWrapper from "./components/PanelWrapper.js";
|
|
|
14
17
|
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
15
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
19
|
import _ from "lodash";
|
|
17
|
-
import { usePrevious
|
|
20
|
+
import { usePrevious } from "ahooks";
|
|
18
21
|
//#region src/MemberPicker/index.tsx
|
|
19
22
|
var DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;
|
|
20
23
|
var Component = (props) => {
|
|
@@ -22,10 +25,13 @@ var Component = (props) => {
|
|
|
22
25
|
const t = getTranslator(locale);
|
|
23
26
|
const { value, type = EMemberPicker.USER, onChange, multiple, dropdownWidth, open, onOpenChange, placeholder = t.MemberPicker.select, className, allowClear, disabled, onClear, size, prefix: propPrefix, lockedIds = [], footer, onCancel, filterItem, mode: propsMode, renderItem, renderSelectedTag, "data-testid": dataTestId, "aria-label": ariaLabel, ...restProps } = props;
|
|
24
27
|
const allowOverlap = props.allowOverlap ?? false;
|
|
25
|
-
const { getUsersByIds, getUsersByKeywords } = AldCustomConfigProvider.useGetUserList();
|
|
28
|
+
const { getUsersByIds, getUsersByKeywords, getUsersByKeywordsWithMeta, getNextLevelGroup, getNextLevelGroupWithMeta } = AldCustomConfigProvider.useGetUserList();
|
|
29
|
+
const inheritedDisabled = useContext(DisabledContext);
|
|
30
|
+
const isDisabled = disabled ?? inheritedDisabled;
|
|
31
|
+
const usesDialog = !!multiple;
|
|
32
|
+
const usesGroupQuery = (type === EMemberPicker.GROUP || !getUsersByKeywords && !getUsersByKeywordsWithMeta) && !!(getNextLevelGroup || getNextLevelGroupWithMeta);
|
|
26
33
|
const [selectedUserList, setSelectedUserList] = useState([]);
|
|
27
34
|
const prevValue = usePrevious(value);
|
|
28
|
-
const [searchUserList, setSearchUserList] = useState([]);
|
|
29
35
|
const [searchString, setSearchString] = useState("");
|
|
30
36
|
const [dropdownContentWidth, setDropdownContentWidth] = useState(dropdownWidth);
|
|
31
37
|
const selectOwnerRef = useRef(null);
|
|
@@ -36,25 +42,20 @@ var Component = (props) => {
|
|
|
36
42
|
}, []);
|
|
37
43
|
const [dropdownOpen, setDropdownOpen] = useState(!!open);
|
|
38
44
|
const queryByKeywords = useMemo(() => {
|
|
45
|
+
if (getUsersByKeywordsWithMeta) return getUsersByKeywordsWithMeta;
|
|
39
46
|
if (getUsersByKeywords) return getUsersByKeywords;
|
|
40
47
|
return (_params = {}) => Promise.reject({ message: t.MemberPicker.pleaseConfigGetUserByKeywordsMethod });
|
|
41
|
-
}, [
|
|
48
|
+
}, [
|
|
49
|
+
getUsersByKeywords,
|
|
50
|
+
getUsersByKeywordsWithMeta,
|
|
51
|
+
t.MemberPicker.pleaseConfigGetUserByKeywordsMethod
|
|
52
|
+
]);
|
|
42
53
|
const queryByIds = useMemo(() => {
|
|
43
54
|
if (getUsersByIds) return getUsersByIds;
|
|
44
55
|
return (_params = {}) => Promise.reject({ message: t.MemberPicker.pleaseConfigGetUserByIdsMethod });
|
|
45
56
|
}, [getUsersByIds, t.MemberPicker.pleaseConfigGetUserByIdsMethod]);
|
|
46
|
-
const { loading,
|
|
47
|
-
|
|
48
|
-
manual: true,
|
|
49
|
-
cacheKey: "member-selector",
|
|
50
|
-
cacheTime: 1e3 * 60 * 2,
|
|
51
|
-
onSuccess: (result) => {
|
|
52
|
-
setSearchUserList(result);
|
|
53
|
-
},
|
|
54
|
-
onError: (error) => {
|
|
55
|
-
message.error(error.message);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
57
|
+
const { result: searchResult, loading, failed, retry } = useMemberSearch(queryByKeywords, searchString, dropdownOpen && !usesGroupQuery && !usesDialog);
|
|
58
|
+
const searchUserList = searchResult.items;
|
|
58
59
|
const totalUserList = useMemo(() => {
|
|
59
60
|
const totalUsers = searchUserList.concat(selectedUserList.filter((item) => {
|
|
60
61
|
return ((item.type === EUserType.USER ? item.nickname : item.name) || "").toUpperCase().includes(searchString.trim().toUpperCase());
|
|
@@ -72,14 +73,6 @@ var Component = (props) => {
|
|
|
72
73
|
searchUserList,
|
|
73
74
|
selectedUserList
|
|
74
75
|
]);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (!dropdownOpen) return;
|
|
77
|
-
run();
|
|
78
|
-
}, [
|
|
79
|
-
dropdownOpen,
|
|
80
|
-
run,
|
|
81
|
-
searchString
|
|
82
|
-
]);
|
|
83
76
|
useEffect(() => {
|
|
84
77
|
if (_.isEqual(value, prevValue)) return;
|
|
85
78
|
if (Array.isArray(value) && (isUser(value[0]) || isUserGroup(value[0]))) setSelectedUserList(value);
|
|
@@ -149,9 +142,15 @@ var Component = (props) => {
|
|
|
149
142
|
}
|
|
150
143
|
}, [triggerRef, dropdownContentWidth]);
|
|
151
144
|
const onDropdownOpenChange = useCallback((open) => {
|
|
152
|
-
|
|
145
|
+
if (isDisabled) return;
|
|
146
|
+
if (!usesDialog || typeof props.open !== "boolean") setDropdownOpen(open);
|
|
153
147
|
onOpenChange?.(open);
|
|
154
|
-
}, [
|
|
148
|
+
}, [
|
|
149
|
+
isDisabled,
|
|
150
|
+
usesDialog,
|
|
151
|
+
props.open,
|
|
152
|
+
onOpenChange
|
|
153
|
+
]);
|
|
155
154
|
const mode = useMemo(() => {
|
|
156
155
|
if (multiple === true) {
|
|
157
156
|
if (typeof propsMode === "object") return {
|
|
@@ -181,15 +180,15 @@ var Component = (props) => {
|
|
|
181
180
|
listboxId,
|
|
182
181
|
selectOpen
|
|
183
182
|
]);
|
|
184
|
-
return /* @__PURE__ */
|
|
183
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
185
184
|
ref: selectOwnerRef,
|
|
186
185
|
style: { display: "contents" },
|
|
187
|
-
children: /* @__PURE__ */ jsx(Select_default, {
|
|
186
|
+
children: [/* @__PURE__ */ jsx(Select_default, {
|
|
188
187
|
prefix: propPrefix,
|
|
189
188
|
...restProps,
|
|
190
189
|
"data-testid": dataTestId,
|
|
191
190
|
"aria-label": ariaLabel,
|
|
192
|
-
showSearch:
|
|
191
|
+
showSearch: !usesDialog,
|
|
193
192
|
searchValue: searchString,
|
|
194
193
|
onSearch: onSearchValueChange,
|
|
195
194
|
"aria-controls": listboxId,
|
|
@@ -231,7 +230,7 @@ var Component = (props) => {
|
|
|
231
230
|
}
|
|
232
231
|
}
|
|
233
232
|
},
|
|
234
|
-
disabled,
|
|
233
|
+
disabled: isDisabled,
|
|
235
234
|
allowClear,
|
|
236
235
|
onClear: () => {
|
|
237
236
|
setSelectedUserList([]);
|
|
@@ -269,7 +268,7 @@ var Component = (props) => {
|
|
|
269
268
|
};
|
|
270
269
|
}),
|
|
271
270
|
optionLabelProp: multiple ? "label" : "tag",
|
|
272
|
-
open: selectOpen,
|
|
271
|
+
open: usesDialog ? false : selectOpen,
|
|
273
272
|
onOpenChange: onDropdownOpenChange,
|
|
274
273
|
popupMatchSelectWidth: panelWidth,
|
|
275
274
|
allowOverlap,
|
|
@@ -282,6 +281,15 @@ var Component = (props) => {
|
|
|
282
281
|
"aria-label": "Member selection results",
|
|
283
282
|
className: cn({ "ald-member-picker-popup-body": allowOverlap }),
|
|
284
283
|
children: /* @__PURE__ */ jsx(Panel, {
|
|
284
|
+
active: dropdownOpen,
|
|
285
|
+
searchFailed: failed,
|
|
286
|
+
useProvidedGroupSearch: type === EMemberPicker.BOTH && !usesGroupQuery,
|
|
287
|
+
searchFeedback: !usesGroupQuery && /* @__PURE__ */ jsx(SearchFeedback, {
|
|
288
|
+
failed,
|
|
289
|
+
hasMore: searchResult.hasMore,
|
|
290
|
+
pathWarningCode: searchResult.pathWarningCode,
|
|
291
|
+
retry
|
|
292
|
+
}),
|
|
285
293
|
type,
|
|
286
294
|
footer,
|
|
287
295
|
value: selectedUserList,
|
|
@@ -302,11 +310,27 @@ var Component = (props) => {
|
|
|
302
310
|
})
|
|
303
311
|
});
|
|
304
312
|
}
|
|
305
|
-
})
|
|
313
|
+
}), usesDialog && !isDisabled && /* @__PURE__ */ jsx(MemberPickerDialog, {
|
|
314
|
+
open: selectOpen,
|
|
315
|
+
value: value ?? selectedUserList,
|
|
316
|
+
type,
|
|
317
|
+
lockedIds,
|
|
318
|
+
filterItem,
|
|
319
|
+
renderItem,
|
|
320
|
+
renderSelectedTag,
|
|
321
|
+
onChange: (members) => {
|
|
322
|
+
setSelectedUserList(members);
|
|
323
|
+
if (props.multiple) props.onChange?.(members);
|
|
324
|
+
},
|
|
325
|
+
footer,
|
|
326
|
+
onCancel,
|
|
327
|
+
onClose: () => onDropdownOpenChange(false)
|
|
328
|
+
})]
|
|
306
329
|
});
|
|
307
330
|
};
|
|
308
331
|
var MemberSelector = Component;
|
|
309
332
|
MemberSelector.MemberPanel = PanelWrapper;
|
|
333
|
+
MemberSelector.Dialog = MemberPickerDialog;
|
|
310
334
|
//#endregion
|
|
311
335
|
export { MemberSelector as default };
|
|
312
336
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/MemberPicker/index.tsx"],"sourcesContent":["import { usePrevious, useRequest } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport Avatar from '../Avatar';\nimport ConfigProvider from '../ConfigProvider';\nimport './member-picker.css';\nimport {\n EUserType,\n IUser,\n IUserGroup,\n TUser,\n} from '../ConfigProvider/getUserList';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport message from '../message';\nimport Panel from './components/Panel';\nimport MemberPanel from './components/PanelWrapper';\nimport {\n EMemberPicker,\n IMemberPickerProps,\n TUserGroupValue,\n TUserValue,\n} from './interface';\nimport { getId } from './utils';\nimport { isUser, isUserGroup } from './utils/getUsersWithUserId';\nimport Select from '../Select';\nimport { Mode } from '../Select/BaseSelect';\n\nconst DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;\n\nconst Component: React.FC<IMemberPickerProps> = (props) => {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n value,\n type = EMemberPicker.USER,\n onChange,\n multiple,\n dropdownWidth,\n open,\n onOpenChange,\n placeholder = t.MemberPicker.select,\n className,\n allowClear,\n disabled,\n onClear,\n size,\n prefix: propPrefix,\n lockedIds = [],\n footer,\n onCancel,\n filterItem,\n mode: propsMode,\n renderItem,\n renderSelectedTag,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n ...restProps\n } = props;\n const allowOverlap = props.allowOverlap ?? false;\n const { getUsersByIds, getUsersByKeywords } = ConfigProvider.useGetUserList();\n const [selectedUserList, setSelectedUserList] = useState<TUser>([]);\n const prevValue = usePrevious(value);\n const [searchUserList, setSearchUserList] = useState<TUser>([]);\n const [searchString, setSearchString] = useState<string>('');\n const [dropdownContentWidth, setDropdownContentWidth] =\n useState(dropdownWidth);\n const selectOwnerRef = useRef<HTMLDivElement>(null);\n // 单选默认浮窗跟触发器等宽(true),调用方传 dropdownWidth 时用具体数字;\n // 多选默认 480,单条记录只有 头像+nickname 时触发器太窄装不下选中标签,故固定值。\n const panelWidth: number | boolean =\n dropdownWidth ?? (multiple ? DEFAULT_MULTIPLE_DROPDOWN_WIDTH : true);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const onSearchValueChange = useCallback((v: string) => {\n setSearchString(v);\n }, []);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(!!open);\n const queryByKeywords = useMemo(() => {\n if (getUsersByKeywords) {\n return getUsersByKeywords;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByKeywordsMethod,\n });\n }, [getUsersByKeywords, t.MemberPicker.pleaseConfigGetUserByKeywordsMethod]);\n const queryByIds = useMemo(() => {\n if (getUsersByIds) {\n return getUsersByIds;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByIdsMethod,\n });\n }, [getUsersByIds, t.MemberPicker.pleaseConfigGetUserByIdsMethod]);\n const { loading, run } = useRequest(() => queryByKeywords(searchString), {\n refreshDeps: [searchString],\n manual: true,\n cacheKey: 'member-selector',\n cacheTime: 1000 * 60 * 2, // 2分钟内不重复请求\n onSuccess: (result) => {\n setSearchUserList(result);\n },\n onError: (error) => {\n message.error(error.message);\n },\n });\n\n const totalUserList: TUser = useMemo(() => {\n const totalUsers = searchUserList.concat(\n selectedUserList.filter((item) => {\n const name =\n (item.type === EUserType.USER ? item.nickname : item.name) || '';\n\n return name.toUpperCase().includes(searchString.trim().toUpperCase());\n }),\n );\n\n return _.uniqBy(totalUsers, (data: IUser | IUserGroup) => {\n if (data.type === EUserType.USER) return data.userId;\n\n return data.groupId;\n }).filter((item) => {\n if (filterItem) {\n return filterItem(item);\n }\n\n return true;\n });\n }, [filterItem, searchString, searchUserList, selectedUserList]);\n\n useEffect(() => {\n if (!dropdownOpen) return;\n run();\n }, [dropdownOpen, run, searchString]);\n\n useEffect(() => {\n if (_.isEqual(value, prevValue)) {\n return;\n }\n if (Array.isArray(value) && (isUser(value[0]) || isUserGroup(value[0]))) {\n setSelectedUserList(value as TUser);\n } else if (isUser(value) || isUserGroup(value)) {\n setSelectedUserList([value]);\n } else {\n let param: Array<TUserValue | TUserGroupValue> = [];\n if (!value) return;\n if (Array.isArray(value) && value.length === 0) {\n setSelectedUserList([]);\n\n return;\n }\n if (!Array.isArray(value)) {\n param = [value];\n } else {\n param = value;\n }\n queryByIds(param).then((result) => {\n // 如果用户已被删除,则需要展示出id\n const valueNotInResult: TUser = param\n .filter((item) => {\n if (item.type === EUserType.USER) {\n return result\n .filter(isUser)\n .every((user) => user.userId !== item.userId);\n }\n\n return result\n .filter(isUserGroup)\n .every((user) => user.groupId !== item.groupId);\n })\n .map((item) => {\n if (item.type === EUserType.USER) {\n return {\n type: EUserType.USER,\n userId: item.userId,\n } as IUser;\n }\n\n return {\n type: EUserType.USER_GROUP,\n groupId: item.groupId,\n } as IUserGroup;\n });\n\n setSelectedUserList([...result, ...valueNotInResult]);\n });\n }\n }, [value, queryByIds, prevValue]);\n\n const onSelectedChange = useCallback(\n (users: TUser) => {\n if (multiple) {\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n setSelectedUserList(users);\n onChange?.(users[0]);\n }\n setDropdownOpen(false);\n },\n [multiple, onChange, setDropdownOpen],\n );\n\n useEffect(() => {\n if (typeof open === 'boolean') {\n setDropdownOpen(open);\n }\n }, [open]);\n\n useEffect(() => {\n if (!dropdownContentWidth) {\n const resizeEle = triggerRef.current;\n if (!resizeEle) return;\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setDropdownContentWidth(width);\n }\n });\n resizeObserver.observe(resizeEle);\n\n return () => {\n resizeObserver.unobserve(resizeEle);\n };\n }\n }, [triggerRef, dropdownContentWidth]);\n const onDropdownOpenChange = useCallback(\n (open: boolean) => {\n setDropdownOpen(open);\n onOpenChange?.(open);\n },\n [onOpenChange],\n );\n const mode = useMemo(() => {\n if (multiple === true) {\n if (typeof propsMode === 'object')\n return {\n ...(propsMode || {}),\n type: 'multiple',\n responsive: _.isNil(propsMode.responsive)\n ? true\n : propsMode.responsive,\n } as Mode;\n return {\n type: 'multiple',\n responsive: true,\n } as Mode;\n }\n\n return multiple ? (multiple as Mode) : propsMode;\n }, [multiple, propsMode]);\n\n const selectOpen = typeof open === 'boolean' ? open : dropdownOpen;\n const listboxId = `ald-member-picker-listbox-${React.useId().replace(\n /:/g,\n '',\n )}`;\n const activeMember = totalUserList[0];\n const activeMemberId = activeMember\n ? `ald-member-picker-option-${getId(activeMember)}`\n : undefined;\n\n useEffect(() => {\n const owner = selectOwnerRef.current?.querySelector<HTMLElement>(\n '[role=\"combobox\"], input',\n );\n if (!owner) return;\n owner.setAttribute('aria-controls', listboxId);\n if (selectOpen && activeMemberId) {\n owner.setAttribute('aria-activedescendant', activeMemberId);\n } else {\n owner.removeAttribute('aria-activedescendant');\n }\n }, [activeMemberId, listboxId, selectOpen]);\n\n return (\n <div ref={selectOwnerRef} style={{ display: 'contents' }}>\n <Select\n prefix={propPrefix}\n {...restProps}\n data-testid={dataTestId}\n aria-label={ariaLabel}\n showSearch\n searchValue={searchString}\n onSearch={onSearchValueChange}\n aria-controls={listboxId}\n aria-activedescendant={selectOpen ? activeMemberId : undefined}\n size={size}\n className={cn('ald-member-picker-select', className)}\n value={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP) {\n return item.groupId;\n } else {\n return item.userId;\n }\n })}\n onChange={(value) => {\n if (_.isEmpty(value)) {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n } else {\n const valueList = Array.isArray(value) ? value : [value];\n if (multiple) {\n const users = valueList\n .map((item) => {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === item;\n }\n\n return user.groupId === item;\n });\n\n return user;\n })\n .filter(Boolean) as TUser;\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === value;\n }\n\n return user.groupId === value;\n });\n if (user) {\n setSelectedUserList([user]);\n onChange?.(user);\n } else {\n setSelectedUserList([]);\n onChange?.();\n }\n }\n }\n }}\n disabled={disabled}\n allowClear={allowClear}\n onClear={() => {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n onClear?.();\n }}\n popupClassName={cn(\n 'ald-member-picker-popup',\n allowOverlap && 'ald-member-picker-popup-adaptive',\n props.popupClassName,\n )}\n mode={mode}\n options={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP)\n return {\n label: item.name || item.groupId,\n value: item.groupId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar type=\"team\" size={20}>\n {item.name || item.groupId}\n </Avatar>\n {item.name || item.groupId}\n </div>\n ),\n };\n\n return {\n label: item.nickname || item.name || item.userId,\n value: item.userId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar\n size={20}\n src={item.photo}\n type={item.type === EUserType.USER ? 'user' : 'team'}\n >\n {item.nickname || item.name || item.userId}\n </Avatar>\n {item.nickname || item.name || item.userId}\n </div>\n ),\n };\n })}\n optionLabelProp={multiple ? 'label' : 'tag'}\n open={selectOpen}\n onOpenChange={onDropdownOpenChange}\n popupMatchSelectWidth={panelWidth}\n allowOverlap={allowOverlap}\n placeholder={placeholder}\n dropdownRender={() => {\n return (\n <div\n ref={triggerRef}\n id={listboxId}\n role=\"group\"\n aria-label=\"Member selection results\"\n className={cn({\n 'ald-member-picker-popup-body': allowOverlap,\n })}\n >\n <Panel\n type={type}\n footer={footer}\n value={selectedUserList}\n dataList={totalUserList}\n lockedIds={lockedIds}\n multiple={!!multiple}\n loading={loading}\n dropdownWidth={dropdownContentWidth}\n onSearchValueChange={onSearchValueChange}\n onChange={onSelectedChange}\n onCancel={() => {\n onCancel?.();\n setDropdownOpen(false);\n }}\n renderItem={renderItem}\n renderSelectedTag={renderSelectedTag}\n searchValue={searchString}\n ></Panel>\n </div>\n );\n }}\n ></Select>\n </div>\n );\n};\n\nconst MemberSelector = Component as React.FC<IMemberPickerProps> & {\n MemberPanel: typeof MemberPanel;\n};\n\nMemberSelector.MemberPanel = MemberPanel;\nexport default MemberSelector;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/MemberPicker/index.tsx"],"sourcesContent":["import MemberPickerDialog from './dialog/MemberPickerDialog';\nimport DisabledContext from '../ConfigProvider/DisabledContext';\nimport useMemberSearch from './useMemberSearch';\nimport SearchFeedback from './components/SearchFeedback';\nimport { usePrevious } from 'ahooks';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport Avatar from '../Avatar';\nimport ConfigProvider from '../ConfigProvider';\nimport './member-picker.css';\nimport {\n EUserType,\n IUser,\n IUserGroup,\n TUser,\n} from '../ConfigProvider/getUserList';\nimport { LocaleContext, getTranslator } from '../locale/default';\nimport Panel from './components/Panel';\nimport MemberPanel from './components/PanelWrapper';\nimport {\n EMemberPicker,\n IMemberPickerProps,\n TUserGroupValue,\n TUserValue,\n} from './interface';\nimport { getId } from './utils';\nimport { isUser, isUserGroup } from './utils/getUsersWithUserId';\nimport Select from '../Select';\nimport { Mode } from '../Select/BaseSelect';\n\nconst DEFAULT_MULTIPLE_DROPDOWN_WIDTH = 480;\n\nconst Component: React.FC<IMemberPickerProps> = (props) => {\n const { locale } = useContext(LocaleContext);\n const t = getTranslator(locale);\n\n const {\n value,\n type = EMemberPicker.USER,\n onChange,\n multiple,\n dropdownWidth,\n open,\n onOpenChange,\n placeholder = t.MemberPicker.select,\n className,\n allowClear,\n disabled,\n onClear,\n size,\n prefix: propPrefix,\n lockedIds = [],\n footer,\n onCancel,\n filterItem,\n mode: propsMode,\n renderItem,\n renderSelectedTag,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n ...restProps\n } = props;\n const allowOverlap = props.allowOverlap ?? false;\n const {\n getUsersByIds,\n getUsersByKeywords,\n getUsersByKeywordsWithMeta,\n getNextLevelGroup,\n getNextLevelGroupWithMeta,\n } = ConfigProvider.useGetUserList();\n const inheritedDisabled = useContext(DisabledContext);\n const isDisabled = disabled ?? inheritedDisabled;\n // 呈现方式由选择模式唯一决定,多选使用弹窗,单选保持浮窗。\n const usesDialog = !!multiple;\n const usesGroupQuery =\n (type === EMemberPicker.GROUP ||\n (!getUsersByKeywords && !getUsersByKeywordsWithMeta)) &&\n !!(getNextLevelGroup || getNextLevelGroupWithMeta);\n const [selectedUserList, setSelectedUserList] = useState<TUser>([]);\n const prevValue = usePrevious(value);\n const [searchString, setSearchString] = useState<string>('');\n const [dropdownContentWidth, setDropdownContentWidth] =\n useState(dropdownWidth);\n const selectOwnerRef = useRef<HTMLDivElement>(null);\n // 单选默认浮窗跟触发器等宽(true),调用方传 dropdownWidth 时用具体数字;\n // 多选默认 480,单条记录只有 头像+nickname 时触发器太窄装不下选中标签,故固定值。\n const panelWidth: number | boolean =\n dropdownWidth ?? (multiple ? DEFAULT_MULTIPLE_DROPDOWN_WIDTH : true);\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const onSearchValueChange = useCallback((v: string) => {\n setSearchString(v);\n }, []);\n const [dropdownOpen, setDropdownOpen] = useState<boolean>(!!open);\n const queryByKeywords = useMemo(() => {\n if (getUsersByKeywordsWithMeta) return getUsersByKeywordsWithMeta;\n if (getUsersByKeywords) {\n return getUsersByKeywords;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByKeywordsMethod,\n });\n }, [\n getUsersByKeywords,\n getUsersByKeywordsWithMeta,\n t.MemberPicker.pleaseConfigGetUserByKeywordsMethod,\n ]);\n const queryByIds = useMemo(() => {\n if (getUsersByIds) {\n return getUsersByIds;\n }\n\n return (_params = {}) =>\n Promise.reject({\n message: t.MemberPicker.pleaseConfigGetUserByIdsMethod,\n });\n }, [getUsersByIds, t.MemberPicker.pleaseConfigGetUserByIdsMethod]);\n const {\n result: searchResult,\n loading,\n failed,\n retry,\n } = useMemberSearch<IUser | IUserGroup>(\n queryByKeywords,\n searchString,\n dropdownOpen && !usesGroupQuery && !usesDialog,\n );\n const searchUserList = searchResult.items;\n\n const totalUserList: TUser = useMemo(() => {\n const totalUsers = searchUserList.concat(\n selectedUserList.filter((item) => {\n const name =\n (item.type === EUserType.USER ? item.nickname : item.name) || '';\n\n return name.toUpperCase().includes(searchString.trim().toUpperCase());\n }),\n );\n\n return _.uniqBy(totalUsers, (data: IUser | IUserGroup) => {\n if (data.type === EUserType.USER) return data.userId;\n\n return data.groupId;\n }).filter((item) => {\n if (filterItem) {\n return filterItem(item);\n }\n\n return true;\n });\n }, [filterItem, searchString, searchUserList, selectedUserList]);\n\n useEffect(() => {\n if (_.isEqual(value, prevValue)) {\n return;\n }\n if (Array.isArray(value) && (isUser(value[0]) || isUserGroup(value[0]))) {\n setSelectedUserList(value as TUser);\n } else if (isUser(value) || isUserGroup(value)) {\n setSelectedUserList([value]);\n } else {\n let param: Array<TUserValue | TUserGroupValue> = [];\n if (!value) return;\n if (Array.isArray(value) && value.length === 0) {\n setSelectedUserList([]);\n\n return;\n }\n if (!Array.isArray(value)) {\n param = [value];\n } else {\n param = value;\n }\n queryByIds(param).then((result) => {\n // 如果用户已被删除,则需要展示出id\n const valueNotInResult: TUser = param\n .filter((item) => {\n if (item.type === EUserType.USER) {\n return result\n .filter(isUser)\n .every((user) => user.userId !== item.userId);\n }\n\n return result\n .filter(isUserGroup)\n .every((user) => user.groupId !== item.groupId);\n })\n .map((item) => {\n if (item.type === EUserType.USER) {\n return {\n type: EUserType.USER,\n userId: item.userId,\n } as IUser;\n }\n\n return {\n type: EUserType.USER_GROUP,\n groupId: item.groupId,\n } as IUserGroup;\n });\n\n setSelectedUserList([...result, ...valueNotInResult]);\n });\n }\n }, [value, queryByIds, prevValue]);\n\n const onSelectedChange = useCallback(\n (users: TUser) => {\n if (multiple) {\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n setSelectedUserList(users);\n onChange?.(users[0]);\n }\n setDropdownOpen(false);\n },\n [multiple, onChange, setDropdownOpen],\n );\n\n useEffect(() => {\n if (typeof open === 'boolean') {\n setDropdownOpen(open);\n }\n }, [open]);\n\n useEffect(() => {\n if (!dropdownContentWidth) {\n const resizeEle = triggerRef.current;\n if (!resizeEle) return;\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width } = entry.contentRect;\n setDropdownContentWidth(width);\n }\n });\n resizeObserver.observe(resizeEle);\n\n return () => {\n resizeObserver.unobserve(resizeEle);\n };\n }\n }, [triggerRef, dropdownContentWidth]);\n const onDropdownOpenChange = useCallback(\n (open: boolean) => {\n if (isDisabled) return;\n if (!usesDialog || typeof props.open !== 'boolean') setDropdownOpen(open);\n onOpenChange?.(open);\n },\n [isDisabled, usesDialog, props.open, onOpenChange],\n );\n const mode = useMemo(() => {\n if (multiple === true) {\n if (typeof propsMode === 'object')\n return {\n ...(propsMode || {}),\n type: 'multiple',\n responsive: _.isNil(propsMode.responsive)\n ? true\n : propsMode.responsive,\n } as Mode;\n return {\n type: 'multiple',\n responsive: true,\n } as Mode;\n }\n\n return multiple ? (multiple as Mode) : propsMode;\n }, [multiple, propsMode]);\n\n const selectOpen = typeof open === 'boolean' ? open : dropdownOpen;\n const listboxId = `ald-member-picker-listbox-${React.useId().replace(\n /:/g,\n '',\n )}`;\n const activeMember = totalUserList[0];\n const activeMemberId = activeMember\n ? `ald-member-picker-option-${getId(activeMember)}`\n : undefined;\n\n useEffect(() => {\n const owner = selectOwnerRef.current?.querySelector<HTMLElement>(\n '[role=\"combobox\"], input',\n );\n if (!owner) return;\n owner.setAttribute('aria-controls', listboxId);\n if (selectOpen && activeMemberId) {\n owner.setAttribute('aria-activedescendant', activeMemberId);\n } else {\n owner.removeAttribute('aria-activedescendant');\n }\n }, [activeMemberId, listboxId, selectOpen]);\n\n return (\n <div ref={selectOwnerRef} style={{ display: 'contents' }}>\n <Select\n prefix={propPrefix}\n {...restProps}\n data-testid={dataTestId}\n aria-label={ariaLabel}\n showSearch={!usesDialog}\n searchValue={searchString}\n onSearch={onSearchValueChange}\n aria-controls={listboxId}\n aria-activedescendant={selectOpen ? activeMemberId : undefined}\n size={size}\n className={cn('ald-member-picker-select', className)}\n value={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP) {\n return item.groupId;\n } else {\n return item.userId;\n }\n })}\n onChange={(value) => {\n if (_.isEmpty(value)) {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n } else {\n const valueList = Array.isArray(value) ? value : [value];\n if (multiple) {\n const users = valueList\n .map((item) => {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === item;\n }\n\n return user.groupId === item;\n });\n\n return user;\n })\n .filter(Boolean) as TUser;\n setSelectedUserList(users);\n onChange?.(users);\n } else {\n const user = totalUserList.find((user) => {\n if (user.type === EUserType.USER) {\n return user.userId === value;\n }\n\n return user.groupId === value;\n });\n if (user) {\n setSelectedUserList([user]);\n onChange?.(user);\n } else {\n setSelectedUserList([]);\n onChange?.();\n }\n }\n }\n }}\n disabled={isDisabled}\n allowClear={allowClear}\n onClear={() => {\n setSelectedUserList([]);\n if (multiple) {\n onChange?.([]);\n } else {\n onChange?.();\n }\n onClear?.();\n }}\n popupClassName={cn(\n 'ald-member-picker-popup',\n allowOverlap && 'ald-member-picker-popup-adaptive',\n props.popupClassName,\n )}\n mode={mode}\n options={selectedUserList.map((item) => {\n if (item.type === EUserType.USER_GROUP)\n return {\n label: item.name || item.groupId,\n value: item.groupId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar type=\"team\" size={20}>\n {item.name || item.groupId}\n </Avatar>\n {item.name || item.groupId}\n </div>\n ),\n };\n\n return {\n label: item.nickname || item.name || item.userId,\n value: item.userId,\n tag: (\n <div className={'ald-member-picker-tag'}>\n <Avatar\n size={20}\n src={item.photo}\n type={item.type === EUserType.USER ? 'user' : 'team'}\n >\n {item.nickname || item.name || item.userId}\n </Avatar>\n {item.nickname || item.name || item.userId}\n </div>\n ),\n };\n })}\n optionLabelProp={multiple ? 'label' : 'tag'}\n open={usesDialog ? false : selectOpen}\n onOpenChange={onDropdownOpenChange}\n popupMatchSelectWidth={panelWidth}\n allowOverlap={allowOverlap}\n placeholder={placeholder}\n dropdownRender={() => {\n return (\n <div\n ref={triggerRef}\n id={listboxId}\n role=\"group\"\n aria-label=\"Member selection results\"\n className={cn({\n 'ald-member-picker-popup-body': allowOverlap,\n })}\n >\n <Panel\n active={dropdownOpen}\n searchFailed={failed}\n useProvidedGroupSearch={\n type === EMemberPicker.BOTH && !usesGroupQuery\n }\n searchFeedback={\n !usesGroupQuery && (\n <SearchFeedback\n failed={failed}\n hasMore={searchResult.hasMore}\n pathWarningCode={searchResult.pathWarningCode}\n retry={retry}\n />\n )\n }\n type={type}\n footer={footer}\n value={selectedUserList}\n dataList={totalUserList}\n lockedIds={lockedIds}\n multiple={!!multiple}\n loading={loading}\n dropdownWidth={dropdownContentWidth}\n onSearchValueChange={onSearchValueChange}\n onChange={onSelectedChange}\n onCancel={() => {\n onCancel?.();\n setDropdownOpen(false);\n }}\n renderItem={renderItem}\n renderSelectedTag={renderSelectedTag}\n searchValue={searchString}\n ></Panel>\n </div>\n );\n }}\n ></Select>\n {usesDialog && !isDisabled && (\n <MemberPickerDialog\n open={selectOpen}\n value={value ?? selectedUserList}\n type={type}\n lockedIds={lockedIds}\n filterItem={filterItem}\n renderItem={renderItem}\n renderSelectedTag={renderSelectedTag}\n onChange={(members) => {\n setSelectedUserList(members);\n if (props.multiple) props.onChange?.(members);\n }}\n footer={footer}\n onCancel={onCancel}\n onClose={() => onDropdownOpenChange(false)}\n />\n )}\n </div>\n );\n};\n\nconst MemberSelector = Component as React.FC<IMemberPickerProps> & {\n MemberPanel: typeof MemberPanel;\n Dialog: typeof MemberPickerDialog;\n};\n\nMemberSelector.MemberPanel = MemberPanel;\nMemberSelector.Dialog = MemberPickerDialog;\nexport default MemberSelector;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MemberSearchResult } from '../ConfigProvider/getUserList';
|
|
2
|
+
/** 搜索状态只属于当前组件和当前请求;关闭、换关键字后拒绝旧响应回写。 */
|
|
3
|
+
export default function useMemberSearch<T>(query: (keyword: string) => Promise<T[] | MemberSearchResult<T>>, keyword: string, enabled?: boolean): {
|
|
4
|
+
result: MemberSearchResult<T>;
|
|
5
|
+
loading: boolean;
|
|
6
|
+
failed: boolean;
|
|
7
|
+
retry: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState } from "react";
|
|
2
|
+
//#region src/MemberPicker/useMemberSearch.ts
|
|
3
|
+
/** 搜索状态只属于当前组件和当前请求;关闭、换关键字后拒绝旧响应回写。 */
|
|
4
|
+
function useMemberSearch(query, keyword, enabled = true) {
|
|
5
|
+
const [result, setResult] = useState({ items: [] });
|
|
6
|
+
const [loading, setLoading] = useState(false);
|
|
7
|
+
const [failed, setFailed] = useState(false);
|
|
8
|
+
const [revision, setRevision] = useState(0);
|
|
9
|
+
const retry = useCallback(() => setRevision((value) => value + 1), []);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!enabled) {
|
|
12
|
+
setLoading(false);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let active = true;
|
|
16
|
+
setLoading(true);
|
|
17
|
+
setResult({ items: [] });
|
|
18
|
+
setFailed(false);
|
|
19
|
+
const timer = setTimeout(() => {
|
|
20
|
+
query(keyword).then((response) => {
|
|
21
|
+
if (active) setResult(Array.isArray(response) ? { items: response } : response);
|
|
22
|
+
}).catch(() => {
|
|
23
|
+
if (active) {
|
|
24
|
+
setFailed(true);
|
|
25
|
+
setResult({ items: [] });
|
|
26
|
+
}
|
|
27
|
+
}).finally(() => {
|
|
28
|
+
if (active) setLoading(false);
|
|
29
|
+
});
|
|
30
|
+
}, keyword ? 300 : 0);
|
|
31
|
+
return () => {
|
|
32
|
+
active = false;
|
|
33
|
+
clearTimeout(timer);
|
|
34
|
+
};
|
|
35
|
+
}, [
|
|
36
|
+
query,
|
|
37
|
+
keyword,
|
|
38
|
+
enabled,
|
|
39
|
+
revision
|
|
40
|
+
]);
|
|
41
|
+
return {
|
|
42
|
+
result,
|
|
43
|
+
loading,
|
|
44
|
+
failed,
|
|
45
|
+
retry
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { useMemberSearch as default };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=useMemberSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMemberSearch.js","names":[],"sources":["../../src/MemberPicker/useMemberSearch.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { MemberSearchResult } from '../ConfigProvider/getUserList';\n\n/** 搜索状态只属于当前组件和当前请求;关闭、换关键字后拒绝旧响应回写。 */\nexport default function useMemberSearch<T>(\n query: (keyword: string) => Promise<T[] | MemberSearchResult<T>>,\n keyword: string,\n enabled = true,\n) {\n const [result, setResult] = useState<MemberSearchResult<T>>({ items: [] });\n const [loading, setLoading] = useState(false);\n const [failed, setFailed] = useState(false);\n const [revision, setRevision] = useState(0);\n const retry = useCallback(() => setRevision((value) => value + 1), []);\n useEffect(() => {\n if (!enabled) {\n setLoading(false);\n return;\n }\n let active = true;\n setLoading(true);\n setResult({ items: [] });\n setFailed(false);\n const timer = setTimeout(\n () => {\n query(keyword)\n .then((response) => {\n if (active) {\n setResult(\n Array.isArray(response) ? { items: response } : response,\n );\n }\n })\n .catch(() => {\n if (active) {\n setFailed(true);\n setResult({ items: [] });\n }\n })\n .finally(() => {\n if (active) setLoading(false);\n });\n },\n keyword ? 300 : 0,\n );\n return () => {\n active = false;\n clearTimeout(timer);\n };\n }, [query, keyword, enabled, revision]);\n return { result, loading, failed, retry };\n}\n"],"mappings":";;;AAIA,SAAwB,gBACtB,OACA,SACA,UAAU,MACV;CACA,MAAM,CAAC,QAAQ,aAAa,SAAgC,EAAE,OAAO,EAAE,EAAE,CAAC;CAC1E,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,CAAC,UAAU,eAAe,SAAS,EAAE;CAC3C,MAAM,QAAQ,kBAAkB,aAAa,UAAU,QAAQ,EAAE,EAAE,EAAE,CAAC;AACtE,iBAAgB;AACd,MAAI,CAAC,SAAS;AACZ,cAAW,MAAM;AACjB;;EAEF,IAAI,SAAS;AACb,aAAW,KAAK;AAChB,YAAU,EAAE,OAAO,EAAE,EAAE,CAAC;AACxB,YAAU,MAAM;EAChB,MAAM,QAAQ,iBACN;AACJ,SAAM,QAAQ,CACX,MAAM,aAAa;AAClB,QAAI,OACF,WACE,MAAM,QAAQ,SAAS,GAAG,EAAE,OAAO,UAAU,GAAG,SACjD;KAEH,CACD,YAAY;AACX,QAAI,QAAQ;AACV,eAAU,KAAK;AACf,eAAU,EAAE,OAAO,EAAE,EAAE,CAAC;;KAE1B,CACD,cAAc;AACb,QAAI,OAAQ,YAAW,MAAM;KAC7B;KAEN,UAAU,MAAM,EACjB;AACD,eAAa;AACX,YAAS;AACT,gBAAa,MAAM;;IAEpB;EAAC;EAAO;EAAS;EAAS;EAAS,CAAC;AACvC,QAAO;EAAE;EAAQ;EAAS;EAAQ;EAAO"}
|
package/dist/Menu/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface MenuProps {
|
|
|
15
15
|
rootClosing?: boolean;
|
|
16
16
|
/** @internal 由 Dropdown 注入,禁用内部定位/overflow 计算。不支持含 SubMenu 的菜单 */
|
|
17
17
|
externalOverflow?: boolean;
|
|
18
|
+
/** @internal Dropdown 已按实际裁剪区域计算根菜单高度,保留其限制。 */
|
|
19
|
+
preserveRootHeight?: boolean;
|
|
18
20
|
}
|
|
19
21
|
export default function Menu(props: MenuProps): import("react/jsx-runtime").JSX.Element;
|
|
20
22
|
export declare function isHeaderMenuItem(menuItem: MenuItemType): menuItem is MenuHeaderType;
|
package/dist/Menu/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import _ from "lodash";
|
|
|
8
8
|
import { ControlledMenu, MenuDivider, MenuHeader, MenuItem, SubMenu } from "@szhsin/react-menu";
|
|
9
9
|
//#region src/Menu/index.tsx
|
|
10
10
|
function Menu(props) {
|
|
11
|
-
const { className, items, onClick: onMenuClick, onBeforeLeafItemClick, selectedKeys, menuStyle, ariaLabel, initialFocus = "first", onRequestClose, rootClosing = false, externalOverflow } = props;
|
|
11
|
+
const { className, items, onClick: onMenuClick, onBeforeLeafItemClick, selectedKeys, menuStyle, ariaLabel, initialFocus = "first", onRequestClose, rootClosing = false, externalOverflow, preserveRootHeight = false } = props;
|
|
12
12
|
const selectedKeySet = new Set(selectedKeys || []);
|
|
13
13
|
const typeaheadRef = useRef({
|
|
14
14
|
query: "",
|
|
@@ -139,6 +139,7 @@ function Menu(props) {
|
|
|
139
139
|
transitionTimeout: 200,
|
|
140
140
|
submenuOpenDelay: 0,
|
|
141
141
|
submenuCloseDelay: 0,
|
|
142
|
+
setDownOverflow: preserveRootHeight,
|
|
142
143
|
menuStyle: { ...menuStyle },
|
|
143
144
|
anchorRef: ref,
|
|
144
145
|
className: cn(className, "ald-menu", isLeafRootMenu && !externalOverflow && "ald-menu-leaf", !isLeafRootMenu && menuStyle?.maxHeight !== void 0 && !externalOverflow && "ald-menu-scrollable"),
|
|
@@ -166,6 +167,6 @@ function isLeafMenu(menuItems) {
|
|
|
166
167
|
return !_.some(menuItems, (item) => isSubMenuItem(item));
|
|
167
168
|
}
|
|
168
169
|
//#endregion
|
|
169
|
-
export { Menu as default, isDivideMenuItem, isHeaderMenuItem, isSubMenuItem };
|
|
170
|
+
export { Menu as default, isDivideMenuItem, isHeaderMenuItem, isLeafMenu, isSubMenuItem };
|
|
170
171
|
|
|
171
172
|
//# sourceMappingURL=index.js.map
|
package/dist/Menu/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Menu/index.tsx"],"sourcesContent":["import {\n ControlledMenu,\n MenuDivider,\n MenuHeader,\n MenuItem,\n SubMenu,\n} from '@szhsin/react-menu';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { CheckLightLine, ChevronRightLine } from '../Icon';\nimport './menu.css';\n\nexport interface MenuProps {\n onClick?: (info: MenuInfo) => void;\n onBeforeLeafItemClick?: () => void;\n className?: string;\n items: MenuItemType[];\n selectedKeys?: string[];\n menuStyle?: React.CSSProperties;\n /** Accessible name for the command menu when its context is not otherwise clear. */\n ariaLabel?: string;\n /** @internal Requested initial keyboard position when the popup opens. */\n initialFocus?: 'first' | 'last';\n /** @internal Requests that the owning popup close, including on Escape. */\n onRequestClose?: (reason: 'click' | 'cancel' | 'blur' | 'scroll') => void;\n rootClosing?: boolean;\n /** @internal 由 Dropdown 注入,禁用内部定位/overflow 计算。不支持含 SubMenu 的菜单 */\n externalOverflow?: boolean;\n}\n\nexport default function Menu(props: MenuProps) {\n const {\n className,\n items,\n onClick: onMenuClick,\n onBeforeLeafItemClick,\n selectedKeys,\n menuStyle,\n ariaLabel,\n initialFocus = 'first',\n onRequestClose,\n rootClosing = false,\n externalOverflow,\n } = props;\n const selectedKeySet = new Set(selectedKeys || []);\n const typeaheadRef = useRef({ query: '', timestamp: 0 });\n const menuItemFocus = useMemo(\n () => ({ position: initialFocus }),\n [initialFocus],\n );\n const onMenuKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLUListElement>) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n event.key.length !== 1\n ) {\n return;\n }\n\n const now = Date.now();\n const previous = typeaheadRef.current;\n const query = `${now - previous.timestamp > 500 ? '' : previous.query}${\n event.key\n }`.toLocaleLowerCase();\n typeaheadRef.current = { query, timestamp: now };\n\n const menuItems = Array.from(\n event.currentTarget.querySelectorAll<HTMLElement>(\n '[role=\"menuitem\"]:not([aria-hidden=\"true\"]):not([aria-disabled=\"true\"])',\n ),\n );\n const activeIndex = menuItems.indexOf(\n document.activeElement as HTMLElement,\n );\n const orderedItems = [\n ...menuItems.slice(activeIndex + 1),\n ...menuItems.slice(0, activeIndex + 1),\n ];\n const match = orderedItems.find((item) => {\n const accessibleName =\n item.getAttribute('aria-label') || item.textContent || '';\n return accessibleName.trim().toLocaleLowerCase().startsWith(query);\n });\n\n if (match) {\n event.preventDefault();\n match.focus();\n }\n },\n [],\n );\n\n const hasDirectSelectedItem = (items: MenuItemType[]): boolean =>\n items.some((item) => {\n if (isSubMenuItem(item)) {\n return selectedKeySet.has(item.key);\n }\n if (isHeaderMenuItem(item) || isDivideMenuItem(item)) {\n return false;\n }\n return selectedKeySet.has(item.key);\n });\n\n const getMenuItems = (items: MenuItemType[], parentPath: string[] = []) => {\n const isSelectableGroup = hasDirectSelectedItem(items);\n\n return items.map((item, index) => {\n if (isDivideMenuItem(item)) {\n return <MenuDivider key={`divider_${index}`} />;\n }\n if (isHeaderMenuItem(item)) {\n return <MenuHeader key={`header_${index}`}>{item.label}</MenuHeader>;\n }\n const currPath = [...parentPath, item.key];\n const titleStr = _.isString(item.label) ? item.label : '';\n const isSelected = selectedKeys?.includes(item.key);\n\n if (isSubMenuItem(item)) {\n const isLeafSubMenu = isLeafMenu(item.children);\n const subMenuOverflow =\n isLeafSubMenu || menuStyle?.maxHeight !== undefined\n ? 'auto'\n : undefined;\n const subMenuItemLabel = (\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n <div className=\"ald-menu-item-right\">\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-selection-slot\" />\n ) : null}\n <ChevronRightLine size={16} />\n </div>\n </div>\n );\n\n return (\n <SubMenu\n key={item.key}\n label={subMenuItemLabel}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n itemProps={{\n className: isLeafSubMenu\n ? 'ald-menu-submenu-leaf-trigger'\n : undefined,\n }}\n align=\"start\"\n direction=\"right\"\n gap={-8}\n position=\"anchor\"\n shift={0}\n menuStyle={{\n ...menuStyle,\n }}\n menuClassName={cn(\n 'ald-menu-submenu-popup',\n isLeafSubMenu && 'ald-menu-submenu-popup-leaf',\n !isLeafSubMenu &&\n menuStyle?.maxHeight !== undefined &&\n 'ald-menu-submenu-popup-scrollable',\n item.popupClassName,\n rootClosing && 'ald-menu-submenu-popup-root-closing',\n )}\n overflow={subMenuOverflow}\n >\n {getMenuItems(item.children, currPath)}\n </SubMenu>\n );\n }\n\n return (\n <MenuItem\n key={item.key}\n className={cn(item.className, {\n 'ald-menu-item-danger': item.danger,\n 'ald-menu-item-selected': isSelected,\n })}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n onClick={({ syntheticEvent }) => {\n onBeforeLeafItemClick?.();\n const menuInfo = {\n key: item.key,\n keyPath: currPath,\n domEvent: syntheticEvent,\n };\n if (item.onClick) {\n item.onClick(menuInfo);\n }\n if (onMenuClick) {\n onMenuClick(menuInfo);\n }\n }}\n >\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-right\">\n <div\n className={cn(\n 'ald-menu-item-selection-slot',\n isSelected &&\n 'ald-menu-item-selection-slot-selected ald-menu-item-selected-icon',\n )}\n >\n {isSelected ? <CheckLightLine /> : null}\n </div>\n </div>\n ) : null}\n </div>\n </MenuItem>\n );\n });\n };\n\n const ref = useRef(null);\n\n const isLeafRootMenu = isLeafMenu(items);\n const menuOverflow =\n isLeafRootMenu || menuStyle?.maxHeight !== undefined ? 'auto' : undefined;\n\n return (\n <>\n <div style={{ display: 'none' }} ref={ref} />\n <ControlledMenu\n state=\"open\"\n transition={{ open: true, close: true }}\n transitionTimeout={200}\n submenuOpenDelay={0}\n submenuCloseDelay={0}\n menuStyle={{\n ...menuStyle,\n }}\n anchorRef={ref}\n className={cn(\n className,\n 'ald-menu',\n isLeafRootMenu && !externalOverflow && 'ald-menu-leaf',\n !isLeafRootMenu &&\n menuStyle?.maxHeight !== undefined &&\n !externalOverflow &&\n 'ald-menu-scrollable',\n )}\n position={externalOverflow ? 'initial' : 'auto'}\n aria-label={ariaLabel}\n captureFocus\n menuItemFocus={menuItemFocus}\n onKeyDown={onMenuKeyDown}\n onClose={({ reason }) => onRequestClose?.(reason)}\n viewScroll={externalOverflow ? 'initial' : 'auto'}\n overflow={externalOverflow ? 'visible' : menuOverflow}\n >\n {getMenuItems(items || [])}\n </ControlledMenu>\n </>\n );\n}\n\nexport function isHeaderMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuHeaderType {\n return 'type' in menuItem && menuItem.type === 'header';\n}\n\nexport function isDivideMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuDividerType {\n return 'type' in menuItem && menuItem.type === 'divider';\n}\n\nexport function isSubMenuItem(menuItem: MenuItemType): menuItem is SubMenuType {\n return 'children' in menuItem && !!menuItem.children;\n}\n\nexport function isLeafMenu(menuItems: MenuItemType[]) {\n return !_.some(menuItems, (item) => isSubMenuItem(item));\n}\n\nexport type MenuItemType =\n | ItemType\n | MenuDividerType\n | SubMenuType\n | MenuHeaderType;\n\nexport interface ItemType {\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n onClick?: (info: MenuInfo) => void;\n danger?: boolean;\n disabled?: boolean;\n className?: string;\n ariaLabel?: string;\n}\n\nexport interface MenuDividerType {\n key?: string;\n type: 'divider';\n}\n\nexport interface MenuHeaderType {\n key?: string;\n type: 'header';\n label: string;\n}\n\nexport interface SubMenuType {\n children: MenuItemType[];\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n popupClassName?: string;\n disabled?: boolean;\n ariaLabel?: string;\n}\n\nexport interface MenuInfo {\n key: string;\n keyPath: string[];\n domEvent: MouseEvent | KeyboardEvent;\n // 阻止菜单关闭\n keepOpen?: boolean;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Menu/index.tsx"],"sourcesContent":["import {\n ControlledMenu,\n MenuDivider,\n MenuHeader,\n MenuItem,\n SubMenu,\n} from '@szhsin/react-menu';\nimport { cn } from '../lib/utils';\nimport _ from 'lodash';\nimport React, { useCallback, useMemo, useRef } from 'react';\nimport { CheckLightLine, ChevronRightLine } from '../Icon';\nimport './menu.css';\n\nexport interface MenuProps {\n onClick?: (info: MenuInfo) => void;\n onBeforeLeafItemClick?: () => void;\n className?: string;\n items: MenuItemType[];\n selectedKeys?: string[];\n menuStyle?: React.CSSProperties;\n /** Accessible name for the command menu when its context is not otherwise clear. */\n ariaLabel?: string;\n /** @internal Requested initial keyboard position when the popup opens. */\n initialFocus?: 'first' | 'last';\n /** @internal Requests that the owning popup close, including on Escape. */\n onRequestClose?: (reason: 'click' | 'cancel' | 'blur' | 'scroll') => void;\n rootClosing?: boolean;\n /** @internal 由 Dropdown 注入,禁用内部定位/overflow 计算。不支持含 SubMenu 的菜单 */\n externalOverflow?: boolean;\n /** @internal Dropdown 已按实际裁剪区域计算根菜单高度,保留其限制。 */\n preserveRootHeight?: boolean;\n}\n\nexport default function Menu(props: MenuProps) {\n const {\n className,\n items,\n onClick: onMenuClick,\n onBeforeLeafItemClick,\n selectedKeys,\n menuStyle,\n ariaLabel,\n initialFocus = 'first',\n onRequestClose,\n rootClosing = false,\n externalOverflow,\n preserveRootHeight = false,\n } = props;\n const selectedKeySet = new Set(selectedKeys || []);\n const typeaheadRef = useRef({ query: '', timestamp: 0 });\n const menuItemFocus = useMemo(\n () => ({ position: initialFocus }),\n [initialFocus],\n );\n const onMenuKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLUListElement>) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n event.key.length !== 1\n ) {\n return;\n }\n\n const now = Date.now();\n const previous = typeaheadRef.current;\n const query = `${now - previous.timestamp > 500 ? '' : previous.query}${\n event.key\n }`.toLocaleLowerCase();\n typeaheadRef.current = { query, timestamp: now };\n\n const menuItems = Array.from(\n event.currentTarget.querySelectorAll<HTMLElement>(\n '[role=\"menuitem\"]:not([aria-hidden=\"true\"]):not([aria-disabled=\"true\"])',\n ),\n );\n const activeIndex = menuItems.indexOf(\n document.activeElement as HTMLElement,\n );\n const orderedItems = [\n ...menuItems.slice(activeIndex + 1),\n ...menuItems.slice(0, activeIndex + 1),\n ];\n const match = orderedItems.find((item) => {\n const accessibleName =\n item.getAttribute('aria-label') || item.textContent || '';\n return accessibleName.trim().toLocaleLowerCase().startsWith(query);\n });\n\n if (match) {\n event.preventDefault();\n match.focus();\n }\n },\n [],\n );\n\n const hasDirectSelectedItem = (items: MenuItemType[]): boolean =>\n items.some((item) => {\n if (isSubMenuItem(item)) {\n return selectedKeySet.has(item.key);\n }\n if (isHeaderMenuItem(item) || isDivideMenuItem(item)) {\n return false;\n }\n return selectedKeySet.has(item.key);\n });\n\n const getMenuItems = (items: MenuItemType[], parentPath: string[] = []) => {\n const isSelectableGroup = hasDirectSelectedItem(items);\n\n return items.map((item, index) => {\n if (isDivideMenuItem(item)) {\n return <MenuDivider key={`divider_${index}`} />;\n }\n if (isHeaderMenuItem(item)) {\n return <MenuHeader key={`header_${index}`}>{item.label}</MenuHeader>;\n }\n const currPath = [...parentPath, item.key];\n const titleStr = _.isString(item.label) ? item.label : '';\n const isSelected = selectedKeys?.includes(item.key);\n\n if (isSubMenuItem(item)) {\n const isLeafSubMenu = isLeafMenu(item.children);\n const subMenuOverflow =\n isLeafSubMenu || menuStyle?.maxHeight !== undefined\n ? 'auto'\n : undefined;\n const subMenuItemLabel = (\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n <div className=\"ald-menu-item-right\">\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-selection-slot\" />\n ) : null}\n <ChevronRightLine size={16} />\n </div>\n </div>\n );\n\n return (\n <SubMenu\n key={item.key}\n label={subMenuItemLabel}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n itemProps={{\n className: isLeafSubMenu\n ? 'ald-menu-submenu-leaf-trigger'\n : undefined,\n }}\n align=\"start\"\n direction=\"right\"\n gap={-8}\n position=\"anchor\"\n shift={0}\n menuStyle={{\n ...menuStyle,\n }}\n menuClassName={cn(\n 'ald-menu-submenu-popup',\n isLeafSubMenu && 'ald-menu-submenu-popup-leaf',\n !isLeafSubMenu &&\n menuStyle?.maxHeight !== undefined &&\n 'ald-menu-submenu-popup-scrollable',\n item.popupClassName,\n rootClosing && 'ald-menu-submenu-popup-root-closing',\n )}\n overflow={subMenuOverflow}\n >\n {getMenuItems(item.children, currPath)}\n </SubMenu>\n );\n }\n\n return (\n <MenuItem\n key={item.key}\n className={cn(item.className, {\n 'ald-menu-item-danger': item.danger,\n 'ald-menu-item-selected': isSelected,\n })}\n disabled={item.disabled}\n aria-label={item.ariaLabel || titleStr || undefined}\n onClick={({ syntheticEvent }) => {\n onBeforeLeafItemClick?.();\n const menuInfo = {\n key: item.key,\n keyPath: currPath,\n domEvent: syntheticEvent,\n };\n if (item.onClick) {\n item.onClick(menuInfo);\n }\n if (onMenuClick) {\n onMenuClick(menuInfo);\n }\n }}\n >\n <div className=\"ald-menu-item-label\" title={titleStr}>\n {item.icon ? (\n <div className=\"ald-menu-item-label-icon\">{item.icon}</div>\n ) : null}\n <div className=\"ald-menu-item-label-text tw-text-typography-body-dense\">\n {item.label}\n </div>\n {isSelectableGroup ? (\n <div className=\"ald-menu-item-right\">\n <div\n className={cn(\n 'ald-menu-item-selection-slot',\n isSelected &&\n 'ald-menu-item-selection-slot-selected ald-menu-item-selected-icon',\n )}\n >\n {isSelected ? <CheckLightLine /> : null}\n </div>\n </div>\n ) : null}\n </div>\n </MenuItem>\n );\n });\n };\n\n const ref = useRef(null);\n\n const isLeafRootMenu = isLeafMenu(items);\n const menuOverflow =\n isLeafRootMenu || menuStyle?.maxHeight !== undefined ? 'auto' : undefined;\n\n return (\n <>\n <div style={{ display: 'none' }} ref={ref} />\n <ControlledMenu\n state=\"open\"\n transition={{ open: true, close: true }}\n transitionTimeout={200}\n submenuOpenDelay={0}\n submenuCloseDelay={0}\n // Root positioning is owned by the surrounding surface (see menu.css).\n // Keep an explicit caller height: React-Menu otherwise replaces it with\n // its viewport limit. Descendant SubMenus still calculate their own overflow.\n setDownOverflow={preserveRootHeight}\n menuStyle={{\n ...menuStyle,\n }}\n anchorRef={ref}\n className={cn(\n className,\n 'ald-menu',\n isLeafRootMenu && !externalOverflow && 'ald-menu-leaf',\n !isLeafRootMenu &&\n menuStyle?.maxHeight !== undefined &&\n !externalOverflow &&\n 'ald-menu-scrollable',\n )}\n position={externalOverflow ? 'initial' : 'auto'}\n aria-label={ariaLabel}\n captureFocus\n menuItemFocus={menuItemFocus}\n onKeyDown={onMenuKeyDown}\n onClose={({ reason }) => onRequestClose?.(reason)}\n viewScroll={externalOverflow ? 'initial' : 'auto'}\n overflow={externalOverflow ? 'visible' : menuOverflow}\n >\n {getMenuItems(items || [])}\n </ControlledMenu>\n </>\n );\n}\n\nexport function isHeaderMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuHeaderType {\n return 'type' in menuItem && menuItem.type === 'header';\n}\n\nexport function isDivideMenuItem(\n menuItem: MenuItemType,\n): menuItem is MenuDividerType {\n return 'type' in menuItem && menuItem.type === 'divider';\n}\n\nexport function isSubMenuItem(menuItem: MenuItemType): menuItem is SubMenuType {\n return 'children' in menuItem && !!menuItem.children;\n}\n\nexport function isLeafMenu(menuItems: MenuItemType[]) {\n return !_.some(menuItems, (item) => isSubMenuItem(item));\n}\n\nexport type MenuItemType =\n | ItemType\n | MenuDividerType\n | SubMenuType\n | MenuHeaderType;\n\nexport interface ItemType {\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n onClick?: (info: MenuInfo) => void;\n danger?: boolean;\n disabled?: boolean;\n className?: string;\n ariaLabel?: string;\n}\n\nexport interface MenuDividerType {\n key?: string;\n type: 'divider';\n}\n\nexport interface MenuHeaderType {\n key?: string;\n type: 'header';\n label: string;\n}\n\nexport interface SubMenuType {\n children: MenuItemType[];\n key: string;\n label: React.ReactNode;\n icon?: React.ReactNode;\n popupClassName?: string;\n disabled?: boolean;\n ariaLabel?: string;\n}\n\nexport interface MenuInfo {\n key: string;\n keyPath: string[];\n domEvent: MouseEvent | KeyboardEvent;\n // 阻止菜单关闭\n keepOpen?: boolean;\n}\n"],"mappings":"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"}
|
package/dist/Modal/index.js
CHANGED
|
@@ -161,7 +161,7 @@ function OriginModal(props) {
|
|
|
161
161
|
"aria-labelledby": title ? titleId : void 0,
|
|
162
162
|
"aria-describedby": subTitle ? descriptionId : void 0,
|
|
163
163
|
"aria-label": ariaLabel,
|
|
164
|
-
className: cn("ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-
|
|
164
|
+
className: cn("ald-modal ant-modal tw-pointer-events-auto tw-box-border tw-flex tw-flex-col tw-overflow-hidden tw-bg-[var(--background-default)] tw-outline-none", fullscreen ? "ald-modal-fullscreen tw-fixed tw-inset-0 tw-size-full tw-rounded-none tw-border-0 tw-shadow-none" : "tw-rounded-r-75 tw-border tw-border-solid tw-border-[var(--border-default)] tw-shadow-[var(--elevation-bottom-bottom-lg)]", paddingLess && "ald-modal-padding-less", virtualScrollBar && "ald-modal-virtual-scroll-bar", hideHeaderBottomBorder && "ald-modal-hide-header-bottom-border", responsiveBounds && "ald-modal-responsive-bounds", className),
|
|
165
165
|
style: {
|
|
166
166
|
...fullscreen ? {} : {
|
|
167
167
|
width: responsiveBounds ? responsiveBoundsStyle.width : width || DEFAULT_WIDTH,
|