@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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IMemberPickerProps as MemberPickerProps } from '../interface';
|
|
2
|
+
import { TMember, TMemberKey } from './types.js';
|
|
3
|
+
interface IProps {
|
|
4
|
+
selectedByKey: ReadonlyMap<TMemberKey, TMember>;
|
|
5
|
+
onToggle: (member: TMember) => void;
|
|
6
|
+
onToggleAll: (members: readonly TMember[], selected: boolean) => void;
|
|
7
|
+
lockedIds?: MemberPickerProps['lockedIds'];
|
|
8
|
+
filterItem?: MemberPickerProps['filterItem'];
|
|
9
|
+
renderItem?: MemberPickerProps['renderItem'];
|
|
10
|
+
}
|
|
11
|
+
/** 用户组树与跨层搜索共用选择事实源,但互不重置彼此的浏览状态。 */
|
|
12
|
+
export default function UserGroupCandidatePanel({ selectedByKey, onToggle, onToggleAll, lockedIds, filterItem, renderItem, }: IProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import Breadcrumb from "../../Breadcrumb/index.js";
|
|
2
|
+
import Button_default from "../../Button/index.js";
|
|
3
|
+
import Checkbox from "../../Checkbox/index.js";
|
|
4
|
+
import InputSearch from "../../InputSearch/index.js";
|
|
5
|
+
import Empty from "../../Empty/index.js";
|
|
6
|
+
import CustomSpin from "../../Spin/index.js";
|
|
7
|
+
import useDialogLocale from "./useDialogLocale.js";
|
|
8
|
+
import { getMemberKey, isMemberLocked } from "./helper.js";
|
|
9
|
+
import MemberOption from "./MemberOption.js";
|
|
10
|
+
import SearchFeedback from "../components/SearchFeedback.js";
|
|
11
|
+
import { useUserGroupCandidates } from "./useUserGroupCandidates.js";
|
|
12
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
//#region src/MemberPicker/dialog/UserGroupCandidatePanel.tsx
|
|
15
|
+
var LOAD_MORE_THRESHOLD = 32;
|
|
16
|
+
var ROOT_BREADCRUMB_INDEX = -1;
|
|
17
|
+
/** 用户组树与跨层搜索共用选择事实源,但互不重置彼此的浏览状态。 */
|
|
18
|
+
function UserGroupCandidatePanel({ selectedByKey, onToggle, onToggleAll, lockedIds = [], filterItem, renderItem }) {
|
|
19
|
+
const t = useDialogLocale();
|
|
20
|
+
const candidates = useUserGroupCandidates();
|
|
21
|
+
const listRef = useRef(null);
|
|
22
|
+
const isSearching = candidates.keyword.trim().length > 0;
|
|
23
|
+
const groups = useMemo(() => candidates.items.filter((group) => filterItem ? filterItem(group) : true), [candidates.items, filterItem]);
|
|
24
|
+
const selectableGroups = groups.filter((group) => !isMemberLocked(group, lockedIds));
|
|
25
|
+
const selectedCount = selectableGroups.filter((group) => selectedByKey.has(getMemberKey(group))).length;
|
|
26
|
+
const allSelected = selectableGroups.length > 0 && selectedCount === selectableGroups.length;
|
|
27
|
+
const partiallySelected = selectedCount > 0 && !allSelected;
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (!isSearching && listRef.current) listRef.current.scrollTop = candidates.scrollTop;
|
|
30
|
+
}, [
|
|
31
|
+
candidates.breadcrumbPath,
|
|
32
|
+
candidates.scrollTop,
|
|
33
|
+
isSearching
|
|
34
|
+
]);
|
|
35
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
36
|
+
className: "tw-flex tw-h-full tw-min-h-0 tw-flex-col",
|
|
37
|
+
"data-testid": "user-group-candidate-panel",
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsx("div", {
|
|
40
|
+
className: "tw-shrink-0 tw-border-b tw-border-solid tw-border-border-default tw-p-sp-150",
|
|
41
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
42
|
+
className: "tw-flex tw-min-w-0 tw-flex-col tw-gap-sp-150",
|
|
43
|
+
children: [
|
|
44
|
+
!isSearching && candidates.breadcrumbPath.length > 0 ? /* @__PURE__ */ jsx(Breadcrumb, {
|
|
45
|
+
className: "tw-min-w-0 tw-flex-wrap",
|
|
46
|
+
items: [{
|
|
47
|
+
title: t.MemberPickerDialog.root,
|
|
48
|
+
onClick: () => candidates.returnToBreadcrumb(ROOT_BREADCRUMB_INDEX, listRef.current?.scrollTop ?? 0)
|
|
49
|
+
}, ...candidates.breadcrumbPath.map((group, index) => ({
|
|
50
|
+
title: group.name,
|
|
51
|
+
onClick: () => candidates.returnToBreadcrumb(index, listRef.current?.scrollTop ?? 0)
|
|
52
|
+
}))]
|
|
53
|
+
}) : null,
|
|
54
|
+
/* @__PURE__ */ jsx(InputSearch, {
|
|
55
|
+
inputMode: true,
|
|
56
|
+
size: "middle",
|
|
57
|
+
className: "tw-w-full",
|
|
58
|
+
debounce: false,
|
|
59
|
+
value: candidates.keyword,
|
|
60
|
+
placeholder: t.MemberPickerDialog.searchGroupsPlaceholder,
|
|
61
|
+
onChange: candidates.setKeyword,
|
|
62
|
+
onSearch: candidates.setKeyword
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx(Checkbox, {
|
|
65
|
+
size: "small",
|
|
66
|
+
className: "tw-self-start",
|
|
67
|
+
checked: allSelected,
|
|
68
|
+
indeterminate: partiallySelected,
|
|
69
|
+
disabled: candidates.loading || candidates.error || selectableGroups.length === 0,
|
|
70
|
+
onChange: (event) => onToggleAll(selectableGroups, event.target.checked),
|
|
71
|
+
children: allSelected ? t.MemberPickerDialog.deselectCurrent(groups.length) : t.MemberPickerDialog.selectCurrent(groups.length)
|
|
72
|
+
})
|
|
73
|
+
]
|
|
74
|
+
})
|
|
75
|
+
}),
|
|
76
|
+
/* @__PURE__ */ jsx(SearchFeedback, {
|
|
77
|
+
pathWarningCode: candidates.pathWarningCode,
|
|
78
|
+
hasMore: candidates.truncated,
|
|
79
|
+
retry: candidates.retry
|
|
80
|
+
}),
|
|
81
|
+
/* @__PURE__ */ jsxs("div", {
|
|
82
|
+
ref: listRef,
|
|
83
|
+
className: "tw-min-h-0 tw-flex-1 tw-overflow-auto tw-py-sp-100",
|
|
84
|
+
onScroll: (event) => {
|
|
85
|
+
const target = event.currentTarget;
|
|
86
|
+
if (!isSearching) candidates.updateScrollTop(target.scrollTop);
|
|
87
|
+
if (target.scrollHeight - target.scrollTop - target.clientHeight <= LOAD_MORE_THRESHOLD) candidates.loadMore();
|
|
88
|
+
},
|
|
89
|
+
children: [
|
|
90
|
+
candidates.loading ? /* @__PURE__ */ jsx(CustomSpin, {}) : null,
|
|
91
|
+
candidates.error ? /* @__PURE__ */ jsxs("div", {
|
|
92
|
+
className: "tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-center tw-gap-2",
|
|
93
|
+
children: [/* @__PURE__ */ jsx("span", { children: t.MemberPickerDialog.loadFailed }), /* @__PURE__ */ jsx(Button_default, {
|
|
94
|
+
type: "link",
|
|
95
|
+
onClick: candidates.retry,
|
|
96
|
+
children: t.MemberPickerDialog.retry
|
|
97
|
+
})]
|
|
98
|
+
}) : null,
|
|
99
|
+
!candidates.loading && !candidates.error && !groups.length ? /* @__PURE__ */ jsx(Empty, { description: t.MemberPickerDialog.emptyCandidates }) : null,
|
|
100
|
+
!candidates.loading && !candidates.error ? groups.map((group) => /* @__PURE__ */ jsx(MemberOption, {
|
|
101
|
+
member: group,
|
|
102
|
+
searchValue: candidates.keyword,
|
|
103
|
+
selected: selectedByKey.has(getMemberKey(group)),
|
|
104
|
+
locked: isMemberLocked(group, lockedIds),
|
|
105
|
+
onToggle,
|
|
106
|
+
onOpenGroup: isSearching ? void 0 : () => {
|
|
107
|
+
const sourceGroup = candidates.items.find((item) => item.groupId === group.groupId);
|
|
108
|
+
if (sourceGroup) candidates.enterGroup(sourceGroup, listRef.current?.scrollTop ?? 0);
|
|
109
|
+
},
|
|
110
|
+
renderItem
|
|
111
|
+
}, group.groupId)) : null,
|
|
112
|
+
!candidates.loading && !candidates.error && candidates.hasMore && !candidates.loadMoreError ? /* @__PURE__ */ jsx(Button_default, {
|
|
113
|
+
type: "link",
|
|
114
|
+
loading: candidates.loadingMore,
|
|
115
|
+
onClick: candidates.loadMore,
|
|
116
|
+
children: t.MemberPickerDialog.loadMore
|
|
117
|
+
}) : null,
|
|
118
|
+
candidates.loadMoreError ? /* @__PURE__ */ jsxs("div", {
|
|
119
|
+
className: "tw-flex tw-items-center tw-justify-center tw-gap-2 tw-py-2",
|
|
120
|
+
children: [/* @__PURE__ */ jsx("span", { children: t.MemberPickerDialog.loadMoreFailed }), /* @__PURE__ */ jsx(Button_default, {
|
|
121
|
+
type: "link",
|
|
122
|
+
onClick: candidates.retryLoadMore,
|
|
123
|
+
children: t.MemberPickerDialog.retry
|
|
124
|
+
})]
|
|
125
|
+
}) : null
|
|
126
|
+
]
|
|
127
|
+
})
|
|
128
|
+
]
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { UserGroupCandidatePanel as default };
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=UserGroupCandidatePanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserGroupCandidatePanel.js","names":[],"sources":["../../../src/MemberPicker/dialog/UserGroupCandidatePanel.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef } from 'react';\nimport Breadcrumb from '../../Breadcrumb';\nimport Button from '../../Button';\nimport Checkbox from '../../Checkbox';\nimport Empty from '../../Empty';\nimport InputSearch from '../../InputSearch';\nimport Spin from '../../Spin';\nimport type { IMemberPickerProps as MemberPickerProps } from '../interface';\nimport useDialogLocale from './useDialogLocale';\nimport { getMemberKey, isMemberLocked } from './helper';\nimport SearchFeedback from '../components/SearchFeedback';\nimport MemberOption from './MemberOption';\nimport type { TMember, TMemberKey } from './types';\nimport { useUserGroupCandidates } from './useUserGroupCandidates';\n\nconst LOAD_MORE_THRESHOLD = 32;\nconst ROOT_BREADCRUMB_INDEX = -1;\n\ninterface IProps {\n selectedByKey: ReadonlyMap<TMemberKey, TMember>;\n onToggle: (member: TMember) => void;\n onToggleAll: (members: readonly TMember[], selected: boolean) => void;\n lockedIds?: MemberPickerProps['lockedIds'];\n filterItem?: MemberPickerProps['filterItem'];\n renderItem?: MemberPickerProps['renderItem'];\n}\n\n/** 用户组树与跨层搜索共用选择事实源,但互不重置彼此的浏览状态。 */\nexport default function UserGroupCandidatePanel({\n selectedByKey,\n onToggle,\n onToggleAll,\n lockedIds = [],\n filterItem,\n renderItem,\n}: IProps) {\n const t = useDialogLocale();\n const candidates = useUserGroupCandidates();\n const listRef = useRef<HTMLDivElement>(null);\n const isSearching = candidates.keyword.trim().length > 0;\n const groups = useMemo(\n () =>\n candidates.items.filter((group) =>\n filterItem ? filterItem(group) : true,\n ),\n [candidates.items, filterItem],\n );\n const selectableGroups = groups.filter(\n (group) => !isMemberLocked(group, lockedIds),\n );\n const selectedCount = selectableGroups.filter((group) =>\n selectedByKey.has(getMemberKey(group)),\n ).length;\n const allSelected =\n selectableGroups.length > 0 && selectedCount === selectableGroups.length;\n const partiallySelected = selectedCount > 0 && !allSelected;\n\n useEffect(() => {\n if (!isSearching && listRef.current) {\n listRef.current.scrollTop = candidates.scrollTop;\n }\n }, [candidates.breadcrumbPath, candidates.scrollTop, isSearching]);\n\n return (\n <section\n className=\"tw-flex tw-h-full tw-min-h-0 tw-flex-col\"\n data-testid=\"user-group-candidate-panel\"\n >\n <div className=\"tw-shrink-0 tw-border-b tw-border-solid tw-border-border-default tw-p-sp-150\">\n <div className=\"tw-flex tw-min-w-0 tw-flex-col tw-gap-sp-150\">\n {!isSearching && candidates.breadcrumbPath.length > 0 ? (\n <Breadcrumb\n className=\"tw-min-w-0 tw-flex-wrap\"\n items={[\n {\n title: t.MemberPickerDialog.root,\n onClick: () =>\n candidates.returnToBreadcrumb(\n ROOT_BREADCRUMB_INDEX,\n listRef.current?.scrollTop ?? 0,\n ),\n },\n ...candidates.breadcrumbPath.map((group, index) => ({\n title: group.name,\n onClick: () =>\n candidates.returnToBreadcrumb(\n index,\n listRef.current?.scrollTop ?? 0,\n ),\n })),\n ]}\n />\n ) : null}\n <InputSearch\n inputMode\n size=\"middle\"\n className=\"tw-w-full\"\n debounce={false}\n value={candidates.keyword}\n placeholder={t.MemberPickerDialog.searchGroupsPlaceholder}\n onChange={candidates.setKeyword}\n onSearch={candidates.setKeyword}\n />\n <Checkbox\n size=\"small\"\n className=\"tw-self-start\"\n checked={allSelected}\n indeterminate={partiallySelected}\n disabled={\n candidates.loading ||\n candidates.error ||\n selectableGroups.length === 0\n }\n onChange={(event) =>\n onToggleAll(selectableGroups, event.target.checked)\n }\n >\n {allSelected\n ? t.MemberPickerDialog.deselectCurrent(groups.length)\n : t.MemberPickerDialog.selectCurrent(groups.length)}\n </Checkbox>\n </div>\n </div>\n <SearchFeedback\n pathWarningCode={candidates.pathWarningCode}\n hasMore={candidates.truncated}\n retry={candidates.retry}\n />\n <div\n ref={listRef}\n className=\"tw-min-h-0 tw-flex-1 tw-overflow-auto tw-py-sp-100\"\n onScroll={(event) => {\n const target = event.currentTarget;\n if (!isSearching) {\n candidates.updateScrollTop(target.scrollTop);\n }\n if (\n target.scrollHeight - target.scrollTop - target.clientHeight <=\n LOAD_MORE_THRESHOLD\n ) {\n candidates.loadMore();\n }\n }}\n >\n {candidates.loading ? <Spin /> : null}\n {candidates.error ? (\n <div className=\"tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-center tw-gap-2\">\n <span>{t.MemberPickerDialog.loadFailed}</span>\n <Button type=\"link\" onClick={candidates.retry}>\n {t.MemberPickerDialog.retry}\n </Button>\n </div>\n ) : null}\n {!candidates.loading && !candidates.error && !groups.length ? (\n <Empty description={t.MemberPickerDialog.emptyCandidates} />\n ) : null}\n {!candidates.loading && !candidates.error\n ? groups.map((group) => (\n <MemberOption\n key={group.groupId}\n member={group}\n searchValue={candidates.keyword}\n selected={selectedByKey.has(getMemberKey(group))}\n locked={isMemberLocked(group, lockedIds)}\n onToggle={onToggle}\n onOpenGroup={\n isSearching\n ? undefined\n : () => {\n const sourceGroup = candidates.items.find(\n (item) => item.groupId === group.groupId,\n );\n if (sourceGroup) {\n candidates.enterGroup(\n sourceGroup,\n listRef.current?.scrollTop ?? 0,\n );\n }\n }\n }\n renderItem={renderItem}\n />\n ))\n : null}\n {!candidates.loading &&\n !candidates.error &&\n candidates.hasMore &&\n !candidates.loadMoreError ? (\n <Button\n type=\"link\"\n loading={candidates.loadingMore}\n onClick={candidates.loadMore}\n >\n {t.MemberPickerDialog.loadMore}\n </Button>\n ) : null}\n {candidates.loadMoreError ? (\n <div className=\"tw-flex tw-items-center tw-justify-center tw-gap-2 tw-py-2\">\n <span>{t.MemberPickerDialog.loadMoreFailed}</span>\n <Button type=\"link\" onClick={candidates.retryLoadMore}>\n {t.MemberPickerDialog.retry}\n </Button>\n </div>\n ) : null}\n </div>\n </section>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IUserGroup, TUserGroupValue, TUserValue } from '../../ConfigProvider/getUserList';
|
|
2
|
+
import { TMember, TMemberKey } from './types.js';
|
|
3
|
+
/** 用户和用户组可能复用同一 ID,因此唯一键必须包含成员类型。 */
|
|
4
|
+
export declare function getMemberKey(member: TMember): TMemberKey;
|
|
5
|
+
/** 从外部值创建独立草稿,并以首次出现顺序为准去重。 */
|
|
6
|
+
export declare function createSelectedByKey(members: readonly TMember[]): Map<TMemberKey, TMember>;
|
|
7
|
+
/** 增加候选时始终创建新 Map,重复项保持原插入位置。 */
|
|
8
|
+
export declare function addSelectedMember(selectedByKey: ReadonlyMap<TMemberKey, TMember>, member: TMember): Map<TMemberKey, TMember>;
|
|
9
|
+
/** 锁定项按类型化 key 判断,用户 ID 与用户组 ID 均受保护。 */
|
|
10
|
+
export declare function removeSelectedMember(selectedByKey: ReadonlyMap<TMemberKey, TMember>, member: TMember, lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>): Map<TMemberKey, TMember>;
|
|
11
|
+
/** 批量更新当前候选,保留候选范围外的选择,并在取消选择时保护锁定项。 */
|
|
12
|
+
export declare function setMembersSelected(selectedByKey: ReadonlyMap<TMemberKey, TMember>, members: readonly TMember[], selected: boolean, lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>): Map<TMemberKey, TMember>;
|
|
13
|
+
/** lockedIds 与成员使用同一类型化 key,避免不同类型的相同 ID 相互锁定。 */
|
|
14
|
+
export declare function isMemberLocked(member: TMember, lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>): boolean;
|
|
15
|
+
/** 合并分页结果时按 groupId 去重,并保留每个用户组首次出现的位置。 */
|
|
16
|
+
export declare function mergeGroupPages(currentItems: readonly IUserGroup[], nextItems: readonly IUserGroup[]): IUserGroup[];
|
|
17
|
+
/** 是否仍有下一页由调用方分页契约明确提供。 */
|
|
18
|
+
export declare const hasMoreGroupPages: (page: {
|
|
19
|
+
hasMore: boolean;
|
|
20
|
+
}) => boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { EUserType } from "../../ConfigProvider/getUserList.js";
|
|
2
|
+
//#region src/MemberPicker/dialog/helper.ts
|
|
3
|
+
/** 用户和用户组可能复用同一 ID,因此唯一键必须包含成员类型。 */
|
|
4
|
+
function getMemberKey(member) {
|
|
5
|
+
const id = member.type === EUserType.USER ? member.userId : member.groupId;
|
|
6
|
+
return `${member.type}:${id}`;
|
|
7
|
+
}
|
|
8
|
+
/** 从外部值创建独立草稿,并以首次出现顺序为准去重。 */
|
|
9
|
+
function createSelectedByKey(members) {
|
|
10
|
+
return members.reduce((selected, member) => {
|
|
11
|
+
const key = getMemberKey(member);
|
|
12
|
+
if (!selected.has(key)) selected.set(key, member);
|
|
13
|
+
return selected;
|
|
14
|
+
}, /* @__PURE__ */ new Map());
|
|
15
|
+
}
|
|
16
|
+
/** 增加候选时始终创建新 Map,重复项保持原插入位置。 */
|
|
17
|
+
function addSelectedMember(selectedByKey, member) {
|
|
18
|
+
const nextSelectedByKey = new Map(selectedByKey);
|
|
19
|
+
const key = getMemberKey(member);
|
|
20
|
+
if (!nextSelectedByKey.has(key)) nextSelectedByKey.set(key, member);
|
|
21
|
+
return nextSelectedByKey;
|
|
22
|
+
}
|
|
23
|
+
/** 锁定项按类型化 key 判断,用户 ID 与用户组 ID 均受保护。 */
|
|
24
|
+
function removeSelectedMember(selectedByKey, member, lockedIds) {
|
|
25
|
+
const nextSelectedByKey = new Map(selectedByKey);
|
|
26
|
+
const key = getMemberKey(member);
|
|
27
|
+
if (!isMemberLocked(member, lockedIds)) nextSelectedByKey.delete(key);
|
|
28
|
+
return nextSelectedByKey;
|
|
29
|
+
}
|
|
30
|
+
/** 批量更新当前候选,保留候选范围外的选择,并在取消选择时保护锁定项。 */
|
|
31
|
+
function setMembersSelected(selectedByKey, members, selected, lockedIds) {
|
|
32
|
+
return members.reduce((nextSelectedByKey, member) => {
|
|
33
|
+
const key = getMemberKey(member);
|
|
34
|
+
if (isMemberLocked(member, lockedIds)) return nextSelectedByKey;
|
|
35
|
+
if (selected) {
|
|
36
|
+
if (!nextSelectedByKey.has(key)) nextSelectedByKey.set(key, member);
|
|
37
|
+
return nextSelectedByKey;
|
|
38
|
+
}
|
|
39
|
+
nextSelectedByKey.delete(key);
|
|
40
|
+
return nextSelectedByKey;
|
|
41
|
+
}, new Map(selectedByKey));
|
|
42
|
+
}
|
|
43
|
+
/** lockedIds 与成员使用同一类型化 key,避免不同类型的相同 ID 相互锁定。 */
|
|
44
|
+
function isMemberLocked(member, lockedIds) {
|
|
45
|
+
const key = getMemberKey(member);
|
|
46
|
+
return lockedIds.some((lockedMember) => getMemberKey(lockedMember) === key);
|
|
47
|
+
}
|
|
48
|
+
/** 合并分页结果时按 groupId 去重,并保留每个用户组首次出现的位置。 */
|
|
49
|
+
function mergeGroupPages(currentItems, nextItems) {
|
|
50
|
+
const groupsById = [...currentItems, ...nextItems].reduce((groups, group) => {
|
|
51
|
+
if (!groups.has(group.groupId)) groups.set(group.groupId, group);
|
|
52
|
+
return groups;
|
|
53
|
+
}, /* @__PURE__ */ new Map());
|
|
54
|
+
return Array.from(groupsById.values());
|
|
55
|
+
}
|
|
56
|
+
/** 是否仍有下一页由调用方分页契约明确提供。 */
|
|
57
|
+
var hasMoreGroupPages = (page) => page.hasMore;
|
|
58
|
+
//#endregion
|
|
59
|
+
export { addSelectedMember, createSelectedByKey, getMemberKey, hasMoreGroupPages, isMemberLocked, mergeGroupPages, removeSelectedMember, setMembersSelected };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.js","names":[],"sources":["../../../src/MemberPicker/dialog/helper.ts"],"sourcesContent":["import { EUserType } from '../../ConfigProvider/getUserList';\nimport type { IUserGroup } from '../../ConfigProvider/getUserList';\nimport type {\n TUserGroupValue,\n TUserValue,\n} from '../../ConfigProvider/getUserList';\nimport type { TMember, TMemberKey } from './types';\n\n/** 用户和用户组可能复用同一 ID,因此唯一键必须包含成员类型。 */\nexport function getMemberKey(member: TMember): TMemberKey {\n const id = member.type === EUserType.USER ? member.userId : member.groupId;\n return `${member.type}:${id}`;\n}\n\n/** 从外部值创建独立草稿,并以首次出现顺序为准去重。 */\nexport function createSelectedByKey(\n members: readonly TMember[],\n): Map<TMemberKey, TMember> {\n return members.reduce<Map<TMemberKey, TMember>>((selected, member) => {\n const key = getMemberKey(member);\n if (!selected.has(key)) selected.set(key, member);\n return selected;\n }, new Map());\n}\n\n/** 增加候选时始终创建新 Map,重复项保持原插入位置。 */\nexport function addSelectedMember(\n selectedByKey: ReadonlyMap<TMemberKey, TMember>,\n member: TMember,\n): Map<TMemberKey, TMember> {\n const nextSelectedByKey = new Map(selectedByKey);\n const key = getMemberKey(member);\n if (!nextSelectedByKey.has(key)) {\n nextSelectedByKey.set(key, member);\n }\n return nextSelectedByKey;\n}\n\n/** 锁定项按类型化 key 判断,用户 ID 与用户组 ID 均受保护。 */\nexport function removeSelectedMember(\n selectedByKey: ReadonlyMap<TMemberKey, TMember>,\n member: TMember,\n lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>,\n): Map<TMemberKey, TMember> {\n const nextSelectedByKey = new Map(selectedByKey);\n const key = getMemberKey(member);\n if (!isMemberLocked(member, lockedIds)) {\n nextSelectedByKey.delete(key);\n }\n return nextSelectedByKey;\n}\n\n/** 批量更新当前候选,保留候选范围外的选择,并在取消选择时保护锁定项。 */\nexport function setMembersSelected(\n selectedByKey: ReadonlyMap<TMemberKey, TMember>,\n members: readonly TMember[],\n selected: boolean,\n lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>,\n): Map<TMemberKey, TMember> {\n return members.reduce<Map<TMemberKey, TMember>>(\n (nextSelectedByKey, member) => {\n const key = getMemberKey(member);\n if (isMemberLocked(member, lockedIds)) {\n return nextSelectedByKey;\n }\n if (selected) {\n if (!nextSelectedByKey.has(key)) {\n nextSelectedByKey.set(key, member);\n }\n return nextSelectedByKey;\n }\n nextSelectedByKey.delete(key);\n return nextSelectedByKey;\n },\n new Map(selectedByKey),\n );\n}\n\n/** lockedIds 与成员使用同一类型化 key,避免不同类型的相同 ID 相互锁定。 */\nexport function isMemberLocked(\n member: TMember,\n lockedIds: ReadonlyArray<TUserValue | TUserGroupValue>,\n): boolean {\n const key = getMemberKey(member);\n return lockedIds.some(\n (lockedMember) => getMemberKey(lockedMember as TMember) === key,\n );\n}\n\n/** 合并分页结果时按 groupId 去重,并保留每个用户组首次出现的位置。 */\nexport function mergeGroupPages(\n currentItems: readonly IUserGroup[],\n nextItems: readonly IUserGroup[],\n): IUserGroup[] {\n const groupsById = [...currentItems, ...nextItems].reduce<\n Map<string, IUserGroup>\n >((groups, group) => {\n if (!groups.has(group.groupId)) groups.set(group.groupId, group);\n return groups;\n }, new Map());\n return Array.from(groupsById.values());\n}\n\n/** 是否仍有下一页由调用方分页契约明确提供。 */\nexport const hasMoreGroupPages = (page: { hasMore: boolean }): boolean =>\n page.hasMore;\n"],"mappings":";;;AASA,SAAgB,aAAa,QAA6B;CACxD,MAAM,KAAK,OAAO,SAAS,UAAU,OAAO,OAAO,SAAS,OAAO;AACnE,QAAO,GAAG,OAAO,KAAK,GAAG;;;AAI3B,SAAgB,oBACd,SAC0B;AAC1B,QAAO,QAAQ,QAAkC,UAAU,WAAW;EACpE,MAAM,MAAM,aAAa,OAAO;AAChC,MAAI,CAAC,SAAS,IAAI,IAAI,CAAE,UAAS,IAAI,KAAK,OAAO;AACjD,SAAO;oBACN,IAAI,KAAK,CAAC;;;AAIf,SAAgB,kBACd,eACA,QAC0B;CAC1B,MAAM,oBAAoB,IAAI,IAAI,cAAc;CAChD,MAAM,MAAM,aAAa,OAAO;AAChC,KAAI,CAAC,kBAAkB,IAAI,IAAI,CAC7B,mBAAkB,IAAI,KAAK,OAAO;AAEpC,QAAO;;;AAIT,SAAgB,qBACd,eACA,QACA,WAC0B;CAC1B,MAAM,oBAAoB,IAAI,IAAI,cAAc;CAChD,MAAM,MAAM,aAAa,OAAO;AAChC,KAAI,CAAC,eAAe,QAAQ,UAAU,CACpC,mBAAkB,OAAO,IAAI;AAE/B,QAAO;;;AAIT,SAAgB,mBACd,eACA,SACA,UACA,WAC0B;AAC1B,QAAO,QAAQ,QACZ,mBAAmB,WAAW;EAC7B,MAAM,MAAM,aAAa,OAAO;AAChC,MAAI,eAAe,QAAQ,UAAU,CACnC,QAAO;AAET,MAAI,UAAU;AACZ,OAAI,CAAC,kBAAkB,IAAI,IAAI,CAC7B,mBAAkB,IAAI,KAAK,OAAO;AAEpC,UAAO;;AAET,oBAAkB,OAAO,IAAI;AAC7B,SAAO;IAET,IAAI,IAAI,cAAc,CACvB;;;AAIH,SAAgB,eACd,QACA,WACS;CACT,MAAM,MAAM,aAAa,OAAO;AAChC,QAAO,UAAU,MACd,iBAAiB,aAAa,aAAwB,KAAK,IAC7D;;;AAIH,SAAgB,gBACd,cACA,WACc;CACd,MAAM,aAAa,CAAC,GAAG,cAAc,GAAG,UAAU,CAAC,QAEhD,QAAQ,UAAU;AACnB,MAAI,CAAC,OAAO,IAAI,MAAM,QAAQ,CAAE,QAAO,IAAI,MAAM,SAAS,MAAM;AAChE,SAAO;oBACN,IAAI,KAAK,CAAC;AACb,QAAO,MAAM,KAAK,WAAW,QAAQ,CAAC;;;AAIxC,IAAa,qBAAqB,SAChC,KAAK"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { EMemberPicker } from '../interface';
|
|
2
|
+
import { EUserType, IUser, IUserGroup } from '../../ConfigProvider/getUserList';
|
|
3
|
+
/** 根层没有 parentGroupId,使用显式 key 避免 Map 中混用 undefined。 */
|
|
4
|
+
export declare const ROOT_GROUP_CACHE_KEY = "__ROOT_GROUP__";
|
|
5
|
+
export type TMember = IUser | IUserGroup;
|
|
6
|
+
export type TMemberKey = `${EUserType}:${string}`;
|
|
7
|
+
export type TMemberPickerTab = EMemberPicker.USER | EMemberPicker.GROUP;
|
|
8
|
+
/** 单个树层级的分页缓存,离开层级后仍保留滚动位置和已加载页。 */
|
|
9
|
+
export interface IGroupLevelCache {
|
|
10
|
+
parentGroupId?: string;
|
|
11
|
+
items: IUserGroup[];
|
|
12
|
+
pageNumber: number;
|
|
13
|
+
hasMore: boolean;
|
|
14
|
+
pathWarningCode?: string | null;
|
|
15
|
+
truncated?: boolean;
|
|
16
|
+
scrollTop: number;
|
|
17
|
+
loadingMore: boolean;
|
|
18
|
+
loadMoreError: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** 树浏览状态与搜索状态隔离,清空搜索时可原样恢复浏览上下文。 */
|
|
21
|
+
export interface IGroupTreeState {
|
|
22
|
+
breadcrumbPath: IUserGroup[];
|
|
23
|
+
levelsByParent: Map<string, IGroupLevelCache>;
|
|
24
|
+
}
|
|
25
|
+
export interface IGroupSearchState {
|
|
26
|
+
keyword: string;
|
|
27
|
+
items: IUserGroup[];
|
|
28
|
+
pageNumber: number;
|
|
29
|
+
hasMore: boolean;
|
|
30
|
+
pathWarningCode?: string | null;
|
|
31
|
+
truncated?: boolean;
|
|
32
|
+
loading: boolean;
|
|
33
|
+
loadingMore: boolean;
|
|
34
|
+
error: boolean;
|
|
35
|
+
loadMoreError: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** 弹窗生命周期内的选择草稿,关闭弹窗即整体释放。 */
|
|
38
|
+
export interface IMemberPickerDraftState {
|
|
39
|
+
activeTab: TMemberPickerTab;
|
|
40
|
+
selectedByKey: Map<TMemberKey, TMember>;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/MemberPicker/dialog/types.ts"],"sourcesContent":["import { EMemberPicker } from '../interface';\nimport { EUserType } from '../../ConfigProvider/getUserList';\nimport type { IUser } from '../../ConfigProvider/getUserList';\nimport type { IUserGroup } from '../../ConfigProvider/getUserList';\n\n/** 根层没有 parentGroupId,使用显式 key 避免 Map 中混用 undefined。 */\nexport const ROOT_GROUP_CACHE_KEY = '__ROOT_GROUP__';\n\nexport type TMember = IUser | IUserGroup;\nexport type TMemberKey = `${EUserType}:${string}`;\nexport type TMemberPickerTab = EMemberPicker.USER | EMemberPicker.GROUP;\n\n/** 单个树层级的分页缓存,离开层级后仍保留滚动位置和已加载页。 */\nexport interface IGroupLevelCache {\n parentGroupId?: string;\n items: IUserGroup[];\n pageNumber: number;\n hasMore: boolean;\n pathWarningCode?: string | null;\n truncated?: boolean;\n scrollTop: number;\n loadingMore: boolean;\n loadMoreError: boolean;\n}\n\n/** 树浏览状态与搜索状态隔离,清空搜索时可原样恢复浏览上下文。 */\nexport interface IGroupTreeState {\n breadcrumbPath: IUserGroup[];\n levelsByParent: Map<string, IGroupLevelCache>;\n}\n\nexport interface IGroupSearchState {\n keyword: string;\n items: IUserGroup[];\n pageNumber: number;\n hasMore: boolean;\n pathWarningCode?: string | null;\n truncated?: boolean;\n loading: boolean;\n loadingMore: boolean;\n error: boolean;\n loadMoreError: boolean;\n}\n\n/** 弹窗生命周期内的选择草稿,关闭弹窗即整体释放。 */\nexport interface IMemberPickerDraftState {\n activeTab: TMemberPickerTab;\n selectedByKey: Map<TMemberKey, TMember>;\n}\n"],"mappings":";;AAMA,IAAa,uBAAuB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** 文案由组件库 locale 决定,业务方不必提供 CAN 文案。 */
|
|
2
|
+
export default function useDialogLocale(): {
|
|
3
|
+
locale: string;
|
|
4
|
+
DatePicker: import('rc-picker/es/interface').Locale;
|
|
5
|
+
Empty: {
|
|
6
|
+
noContentFound: string;
|
|
7
|
+
};
|
|
8
|
+
ColorPicker: {
|
|
9
|
+
default: string;
|
|
10
|
+
standardColor: string;
|
|
11
|
+
recentlyUsed: string;
|
|
12
|
+
};
|
|
13
|
+
DataPreviewTable: {
|
|
14
|
+
dataLoadFailed: string;
|
|
15
|
+
loadFailed: string;
|
|
16
|
+
};
|
|
17
|
+
InputSearch: {
|
|
18
|
+
search: string;
|
|
19
|
+
};
|
|
20
|
+
MemberPickerDialog: {
|
|
21
|
+
missingGroupSource: string;
|
|
22
|
+
missingUserSource: string;
|
|
23
|
+
loadMore: string;
|
|
24
|
+
resizePanels: string;
|
|
25
|
+
title: string;
|
|
26
|
+
user: string;
|
|
27
|
+
userGroup: string;
|
|
28
|
+
selected: string;
|
|
29
|
+
root: string;
|
|
30
|
+
subLevel: string;
|
|
31
|
+
searchUsersPlaceholder: string;
|
|
32
|
+
searchGroupsPlaceholder: string;
|
|
33
|
+
selectCurrent: (count: number) => string;
|
|
34
|
+
deselectCurrent: (count: number) => string;
|
|
35
|
+
emptyCandidates: string;
|
|
36
|
+
emptySelected: string;
|
|
37
|
+
loadFailed: string;
|
|
38
|
+
retry: string;
|
|
39
|
+
loadMoreFailed: string;
|
|
40
|
+
maximize: string;
|
|
41
|
+
exitMaximize: string;
|
|
42
|
+
ok: string;
|
|
43
|
+
cancel: string;
|
|
44
|
+
};
|
|
45
|
+
MemberPicker: {
|
|
46
|
+
searchFailed: string;
|
|
47
|
+
pathUnavailable: string;
|
|
48
|
+
moreResults: string;
|
|
49
|
+
retry: string;
|
|
50
|
+
select: string;
|
|
51
|
+
ban: string;
|
|
52
|
+
pleaseConfigGetUserByKeywordsMethod: string;
|
|
53
|
+
pleaseConfigGetUserByIdsMethod: string;
|
|
54
|
+
noData: string;
|
|
55
|
+
subLevel: string;
|
|
56
|
+
users: string;
|
|
57
|
+
userGroups: string;
|
|
58
|
+
selectedTotal: (total: number) => string;
|
|
59
|
+
cancel: string;
|
|
60
|
+
confirm: string;
|
|
61
|
+
};
|
|
62
|
+
Modal: {
|
|
63
|
+
cancel: string;
|
|
64
|
+
sure: string;
|
|
65
|
+
};
|
|
66
|
+
Select: {
|
|
67
|
+
noSearchResult: string;
|
|
68
|
+
all: string;
|
|
69
|
+
};
|
|
70
|
+
Tree: {
|
|
71
|
+
expand: string;
|
|
72
|
+
};
|
|
73
|
+
Table: {
|
|
74
|
+
cancelSelect: string;
|
|
75
|
+
selected: string;
|
|
76
|
+
item: string;
|
|
77
|
+
selectAll: string;
|
|
78
|
+
};
|
|
79
|
+
ErrorBoundary: {
|
|
80
|
+
happenedError: string;
|
|
81
|
+
};
|
|
82
|
+
LogicTree: {
|
|
83
|
+
btn: {
|
|
84
|
+
addCondition: string;
|
|
85
|
+
addRelation: string;
|
|
86
|
+
};
|
|
87
|
+
select: {
|
|
88
|
+
and: string;
|
|
89
|
+
or: string;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
Pagination: {
|
|
93
|
+
navigationLabel: string;
|
|
94
|
+
previousPage: string;
|
|
95
|
+
nextPage: string;
|
|
96
|
+
page: (page: number) => string;
|
|
97
|
+
currentPage: (page: number) => string;
|
|
98
|
+
pageSize: string;
|
|
99
|
+
itemsPerPage: string;
|
|
100
|
+
selectPageSize: string;
|
|
101
|
+
totalItems: (total: number, range: [number, number]) => string;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LocaleContext, getTranslator } from "../../locale/default.js";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
//#region src/MemberPicker/dialog/useDialogLocale.ts
|
|
4
|
+
/** 文案由组件库 locale 决定,业务方不必提供 CAN 文案。 */
|
|
5
|
+
function useDialogLocale() {
|
|
6
|
+
const { locale } = useContext(LocaleContext);
|
|
7
|
+
return getTranslator(locale);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { useDialogLocale as default };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=useDialogLocale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDialogLocale.js","names":[],"sources":["../../../src/MemberPicker/dialog/useDialogLocale.ts"],"sourcesContent":["import { useContext } from 'react';\nimport { getTranslator, LocaleContext } from '../../locale/default';\n/** 文案由组件库 locale 决定,业务方不必提供 CAN 文案。 */\nexport default function useDialogLocale() {\n const { locale } = useContext(LocaleContext);\n return getTranslator(locale);\n}\n"],"mappings":";;;;AAGA,SAAwB,kBAAkB;CACxC,MAAM,EAAE,WAAW,WAAW,cAAc;AAC5C,QAAO,cAAc,OAAO"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EMemberPicker, TMemberPickerValue as MemberPickerValue } from '../interface';
|
|
2
|
+
import { TUserGroupValue, TUserValue, TUser } from '../../ConfigProvider/getUserList';
|
|
3
|
+
import { TMember, TMemberKey, TMemberPickerTab } from './types.js';
|
|
4
|
+
export interface IUseMemberPickerDraftOptions {
|
|
5
|
+
value?: MemberPickerValue;
|
|
6
|
+
type?: EMemberPicker;
|
|
7
|
+
lockedIds?: Array<TUserValue | TUserGroupValue>;
|
|
8
|
+
onChange?: (members: TUser) => void;
|
|
9
|
+
}
|
|
10
|
+
export interface IMemberPickerDraftResult {
|
|
11
|
+
activeTab: TMemberPickerTab;
|
|
12
|
+
selectedMembers: TUser;
|
|
13
|
+
selectedByKey: Map<TMemberKey, TMember>;
|
|
14
|
+
hydrating: boolean;
|
|
15
|
+
setActiveTab: (tab: TMemberPickerTab) => void;
|
|
16
|
+
toggleMember: (member: TMember) => void;
|
|
17
|
+
toggleMembers: (members: readonly TMember[], selected: boolean) => void;
|
|
18
|
+
removeMember: (member: TMember) => void;
|
|
19
|
+
confirm: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 管理单次弹窗内的成员选择草稿。
|
|
23
|
+
*
|
|
24
|
+
* 外部 value 仅用于初始化,增删不会提前触发 onChange;弹窗取消时卸载本 hook,
|
|
25
|
+
* 只有 confirm 会按 Map 的稳定插入顺序一次性提交。
|
|
26
|
+
*/
|
|
27
|
+
export declare function useMemberPickerDraft({ value, type, lockedIds, onChange, }: IUseMemberPickerDraftOptions): IMemberPickerDraftResult;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { EUserType } from "../../ConfigProvider/getUserList.js";
|
|
2
|
+
import AldCustomConfigProvider from "../../ConfigProvider/index.js";
|
|
3
|
+
import { EMemberPicker } from "../interface.js";
|
|
4
|
+
import { addSelectedMember, createSelectedByKey, getMemberKey, isMemberLocked, removeSelectedMember, setMembersSelected } from "./helper.js";
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
//#region src/MemberPicker/dialog/useMemberPickerDraft.ts
|
|
7
|
+
var EMPTY_LOCKED_IDS = [];
|
|
8
|
+
var toValueArray = (value) => {
|
|
9
|
+
if (!value) return [];
|
|
10
|
+
return Array.isArray(value) ? [...value] : [value];
|
|
11
|
+
};
|
|
12
|
+
/** 历史值可能只有 ID;占位名称保证不可见对象不会被静默丢弃。 */
|
|
13
|
+
var toMemberPlaceholder = (value) => {
|
|
14
|
+
if (value.type === EUserType.USER) return {
|
|
15
|
+
...value,
|
|
16
|
+
type: EUserType.USER,
|
|
17
|
+
name: value.name ?? value.nickname ?? value.account ?? value.userId
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
...value,
|
|
21
|
+
type: EUserType.USER_GROUP,
|
|
22
|
+
name: value.name ?? value.groupId,
|
|
23
|
+
parentId: value.parentId ?? null,
|
|
24
|
+
frontId: value.frontId ?? null
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
var needsHydration = (value) => {
|
|
28
|
+
if (value.type === EUserType.USER) return !value.name && !value.nickname && !value.account;
|
|
29
|
+
return !value.name;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 管理单次弹窗内的成员选择草稿。
|
|
33
|
+
*
|
|
34
|
+
* 外部 value 仅用于初始化,增删不会提前触发 onChange;弹窗取消时卸载本 hook,
|
|
35
|
+
* 只有 confirm 会按 Map 的稳定插入顺序一次性提交。
|
|
36
|
+
*/
|
|
37
|
+
function useMemberPickerDraft({ value, type = EMemberPicker.BOTH, lockedIds = EMPTY_LOCKED_IDS, onChange }) {
|
|
38
|
+
const { getUsersByIds } = AldCustomConfigProvider.useGetUserList();
|
|
39
|
+
const initialValuesRef = useRef(toValueArray(value));
|
|
40
|
+
const missingValuesRef = useRef(initialValuesRef.current.filter(needsHydration));
|
|
41
|
+
const [selectedByKey, setSelectedByKey] = useState(() => createSelectedByKey(initialValuesRef.current.map(toMemberPlaceholder)));
|
|
42
|
+
const [hydrating, setHydrating] = useState(missingValuesRef.current.length > 0 && Boolean(getUsersByIds));
|
|
43
|
+
const [activeTab, setActiveTabState] = useState(type === EMemberPicker.GROUP ? EMemberPicker.GROUP : EMemberPicker.USER);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const missingValues = missingValuesRef.current;
|
|
46
|
+
if (!missingValues.length || !getUsersByIds) {
|
|
47
|
+
setHydrating(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let active = true;
|
|
51
|
+
getUsersByIds(missingValues).then((hydratedMembers) => {
|
|
52
|
+
if (!active) return;
|
|
53
|
+
const hydratedByKey = createSelectedByKey(hydratedMembers.map((member) => toMemberPlaceholder(member)));
|
|
54
|
+
setSelectedByKey((currentSelected) => new Map(Array.from(currentSelected).map(([key, member]) => [key, hydratedByKey.get(key) ?? member])));
|
|
55
|
+
}).catch(() => void 0).finally(() => {
|
|
56
|
+
if (active) setHydrating(false);
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
active = false;
|
|
60
|
+
};
|
|
61
|
+
}, [getUsersByIds]);
|
|
62
|
+
const setActiveTab = useCallback((tab) => {
|
|
63
|
+
if (type === EMemberPicker.BOTH) setActiveTabState(tab);
|
|
64
|
+
}, [type]);
|
|
65
|
+
const removeMember = useCallback((member) => {
|
|
66
|
+
setSelectedByKey((currentSelected) => removeSelectedMember(currentSelected, member, lockedIds));
|
|
67
|
+
}, [lockedIds]);
|
|
68
|
+
const toggleMember = useCallback((member) => {
|
|
69
|
+
if (isMemberLocked(member, lockedIds)) return;
|
|
70
|
+
setSelectedByKey((currentSelected) => {
|
|
71
|
+
const key = getMemberKey(member);
|
|
72
|
+
return currentSelected.has(key) ? removeSelectedMember(currentSelected, member, lockedIds) : addSelectedMember(currentSelected, member);
|
|
73
|
+
});
|
|
74
|
+
}, [lockedIds]);
|
|
75
|
+
const toggleMembers = useCallback((members, selected) => {
|
|
76
|
+
setSelectedByKey((currentSelected) => setMembersSelected(currentSelected, members, selected, lockedIds));
|
|
77
|
+
}, [lockedIds]);
|
|
78
|
+
return {
|
|
79
|
+
activeTab,
|
|
80
|
+
selectedMembers: useMemo(() => Array.from(selectedByKey.values()), [selectedByKey]),
|
|
81
|
+
selectedByKey,
|
|
82
|
+
hydrating,
|
|
83
|
+
setActiveTab,
|
|
84
|
+
toggleMember,
|
|
85
|
+
toggleMembers,
|
|
86
|
+
removeMember,
|
|
87
|
+
confirm: useCallback(() => {
|
|
88
|
+
onChange?.(Array.from(selectedByKey.values()));
|
|
89
|
+
}, [onChange, selectedByKey])
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
export { useMemberPickerDraft };
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=useMemberPickerDraft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMemberPickerDraft.js","names":[],"sources":["../../../src/MemberPicker/dialog/useMemberPickerDraft.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport ConfigProvider from '../../ConfigProvider';\nimport { EMemberPicker } from '../interface';\nimport { EUserType } from '../../ConfigProvider/getUserList';\nimport type { TMemberPickerValue as MemberPickerValue } from '../interface';\nimport type {\n TUserGroupValue,\n TUserValue,\n} from '../../ConfigProvider/getUserList';\nimport type { TUser } from '../../ConfigProvider/getUserList';\nimport {\n addSelectedMember,\n createSelectedByKey,\n getMemberKey,\n isMemberLocked,\n removeSelectedMember,\n setMembersSelected,\n} from './helper';\nimport type { TMember, TMemberKey, TMemberPickerTab } from './types';\n\nconst EMPTY_LOCKED_IDS: Array<TUserValue | TUserGroupValue> = [];\n\nconst toValueArray = (\n value?: MemberPickerValue,\n): Array<TUserValue | TUserGroupValue> => {\n if (!value) {\n return [];\n }\n return Array.isArray(value) ? [...value] : [value];\n};\n\n/** 历史值可能只有 ID;占位名称保证不可见对象不会被静默丢弃。 */\nconst toMemberPlaceholder = (value: TUserValue | TUserGroupValue): TMember => {\n if (value.type === EUserType.USER) {\n return {\n ...value,\n type: EUserType.USER,\n name: value.name ?? value.nickname ?? value.account ?? value.userId,\n };\n }\n return {\n ...value,\n type: EUserType.USER_GROUP,\n name: value.name ?? value.groupId,\n parentId: value.parentId ?? null,\n frontId: value.frontId ?? null,\n };\n};\n\nconst needsHydration = (value: TUserValue | TUserGroupValue): boolean => {\n if (value.type === EUserType.USER) {\n return !value.name && !value.nickname && !value.account;\n }\n return !value.name;\n};\n\nexport interface IUseMemberPickerDraftOptions {\n value?: MemberPickerValue;\n type?: EMemberPicker;\n lockedIds?: Array<TUserValue | TUserGroupValue>;\n onChange?: (members: TUser) => void;\n}\n\nexport interface IMemberPickerDraftResult {\n activeTab: TMemberPickerTab;\n selectedMembers: TUser;\n selectedByKey: Map<TMemberKey, TMember>;\n hydrating: boolean;\n setActiveTab: (tab: TMemberPickerTab) => void;\n toggleMember: (member: TMember) => void;\n toggleMembers: (members: readonly TMember[], selected: boolean) => void;\n removeMember: (member: TMember) => void;\n confirm: () => void;\n}\n\n/**\n * 管理单次弹窗内的成员选择草稿。\n *\n * 外部 value 仅用于初始化,增删不会提前触发 onChange;弹窗取消时卸载本 hook,\n * 只有 confirm 会按 Map 的稳定插入顺序一次性提交。\n */\nexport function useMemberPickerDraft({\n value,\n type = EMemberPicker.BOTH,\n lockedIds = EMPTY_LOCKED_IDS,\n onChange,\n}: IUseMemberPickerDraftOptions): IMemberPickerDraftResult {\n const { getUsersByIds } = ConfigProvider.useGetUserList();\n const initialValuesRef = useRef(toValueArray(value));\n const missingValuesRef = useRef(\n initialValuesRef.current.filter(needsHydration),\n );\n const [selectedByKey, setSelectedByKey] = useState(() =>\n createSelectedByKey(initialValuesRef.current.map(toMemberPlaceholder)),\n );\n const [hydrating, setHydrating] = useState(\n missingValuesRef.current.length > 0 && Boolean(getUsersByIds),\n );\n const [activeTab, setActiveTabState] = useState<TMemberPickerTab>(\n type === EMemberPicker.GROUP ? EMemberPicker.GROUP : EMemberPicker.USER,\n );\n\n useEffect(() => {\n const missingValues = missingValuesRef.current;\n if (!missingValues.length || !getUsersByIds) {\n setHydrating(false);\n return undefined;\n }\n\n let active = true;\n getUsersByIds(missingValues)\n .then((hydratedMembers) => {\n if (!active) {\n return;\n }\n const hydratedByKey = createSelectedByKey(\n hydratedMembers.map((member) => toMemberPlaceholder(member)),\n );\n setSelectedByKey(\n (currentSelected) =>\n new Map(\n Array.from(currentSelected).map(([key, member]) => [\n key,\n hydratedByKey.get(key) ?? member,\n ]),\n ),\n );\n })\n .catch(() => undefined)\n .finally(() => {\n if (active) {\n setHydrating(false);\n }\n });\n\n return () => {\n active = false;\n };\n }, [getUsersByIds]);\n\n const setActiveTab = useCallback(\n (tab: TMemberPickerTab) => {\n if (type === EMemberPicker.BOTH) {\n setActiveTabState(tab);\n }\n },\n [type],\n );\n\n const removeMember = useCallback(\n (member: TMember) => {\n setSelectedByKey((currentSelected) =>\n removeSelectedMember(currentSelected, member, lockedIds),\n );\n },\n [lockedIds],\n );\n\n const toggleMember = useCallback(\n (member: TMember) => {\n if (isMemberLocked(member, lockedIds)) {\n return;\n }\n setSelectedByKey((currentSelected) => {\n const key = getMemberKey(member);\n return currentSelected.has(key)\n ? removeSelectedMember(currentSelected, member, lockedIds)\n : addSelectedMember(currentSelected, member);\n });\n },\n [lockedIds],\n );\n\n const toggleMembers = useCallback(\n (members: readonly TMember[], selected: boolean) => {\n setSelectedByKey((currentSelected) =>\n setMembersSelected(currentSelected, members, selected, lockedIds),\n );\n },\n [lockedIds],\n );\n\n const selectedMembers = useMemo<TUser>(\n () => Array.from(selectedByKey.values()),\n [selectedByKey],\n );\n\n const confirm = useCallback(() => {\n onChange?.(Array.from(selectedByKey.values()));\n }, [onChange, selectedByKey]);\n\n return {\n activeTab,\n selectedMembers,\n selectedByKey,\n hydrating,\n setActiveTab,\n toggleMember,\n toggleMembers,\n removeMember,\n confirm,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { IUserGroup } from '../../ConfigProvider/getUserList';
|
|
2
|
+
export interface IUserGroupCandidatesResult {
|
|
3
|
+
breadcrumbPath: IUserGroup[];
|
|
4
|
+
items: IUserGroup[];
|
|
5
|
+
keyword: string;
|
|
6
|
+
pathWarningCode?: string | null;
|
|
7
|
+
truncated?: boolean;
|
|
8
|
+
loading: boolean;
|
|
9
|
+
loadingMore: boolean;
|
|
10
|
+
error: boolean;
|
|
11
|
+
loadMoreError: boolean;
|
|
12
|
+
hasMore: boolean;
|
|
13
|
+
/** 当前层已保存的滚动位置,供候选面板在层级切换后恢复。 */
|
|
14
|
+
scrollTop: number;
|
|
15
|
+
setKeyword: (keyword: string) => void;
|
|
16
|
+
enterGroup: (group: IUserGroup, scrollTop: number) => void;
|
|
17
|
+
returnToBreadcrumb: (index: number, scrollTop: number) => void;
|
|
18
|
+
loadMore: () => void;
|
|
19
|
+
retry: () => void;
|
|
20
|
+
retryLoadMore: () => void;
|
|
21
|
+
updateScrollTop: (scrollTop: number) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 管理受限用户组树与跨层搜索。
|
|
25
|
+
*
|
|
26
|
+
* 树层级缓存和搜索结果分别持有;所有异步响应都受版本号保护,关闭弹窗、
|
|
27
|
+
* 换词、清空或切换层级后,旧响应只能结束自身,不能覆盖当前界面。
|
|
28
|
+
*/
|
|
29
|
+
export declare function useUserGroupCandidates(): IUserGroupCandidatesResult;
|