@aloudata/aloudata-design 3.1.6 → 3.1.8

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.
Files changed (92) hide show
  1. package/dist/ConfigProvider/getUserList.d.ts +47 -0
  2. package/dist/ConfigProvider/getUserList.js.map +1 -1
  3. package/dist/ConfigProvider/hooks/useGetUserList.d.ts +7 -0
  4. package/dist/ConfigProvider/hooks/useGetUserList.js +5 -1
  5. package/dist/ConfigProvider/hooks/useGetUserList.js.map +1 -1
  6. package/dist/ConfigProvider/index.d.ts +5 -1
  7. package/dist/ConfigProvider/index.js +6 -2
  8. package/dist/ConfigProvider/index.js.map +1 -1
  9. package/dist/Dropdown/index.d.ts +7 -2
  10. package/dist/Dropdown/index.js +52 -18
  11. package/dist/Dropdown/index.js.map +1 -1
  12. package/dist/MemberPicker/components/MultipleOption.d.ts +1 -0
  13. package/dist/MemberPicker/components/MultipleOption.js +3 -1
  14. package/dist/MemberPicker/components/MultipleOption.js.map +1 -1
  15. package/dist/MemberPicker/components/NickLabel.d.ts +5 -0
  16. package/dist/MemberPicker/components/NickLabel.js +14 -4
  17. package/dist/MemberPicker/components/NickLabel.js.map +1 -1
  18. package/dist/MemberPicker/components/Panel.d.ts +6 -1
  19. package/dist/MemberPicker/components/Panel.js +17 -5
  20. package/dist/MemberPicker/components/Panel.js.map +1 -1
  21. package/dist/MemberPicker/components/PanelWrapper.d.ts +3 -2
  22. package/dist/MemberPicker/components/PanelWrapper.js +27 -25
  23. package/dist/MemberPicker/components/PanelWrapper.js.map +1 -1
  24. package/dist/MemberPicker/components/SearchFeedback.d.ts +7 -0
  25. package/dist/MemberPicker/components/SearchFeedback.js +27 -0
  26. package/dist/MemberPicker/components/SearchFeedback.js.map +1 -0
  27. package/dist/MemberPicker/components/SingleOption.d.ts +1 -0
  28. package/dist/MemberPicker/components/SingleOption.js +3 -1
  29. package/dist/MemberPicker/components/SingleOption.js.map +1 -1
  30. package/dist/MemberPicker/components/UserGroupSelection.d.ts +6 -1
  31. package/dist/MemberPicker/components/UserGroupSelection.js +30 -23
  32. package/dist/MemberPicker/components/UserGroupSelection.js.map +1 -1
  33. package/dist/MemberPicker/dialog/DialogColumns.d.ts +5 -0
  34. package/dist/MemberPicker/dialog/DialogColumns.js +59 -0
  35. package/dist/MemberPicker/dialog/DialogColumns.js.map +1 -0
  36. package/dist/MemberPicker/dialog/DialogContent.d.ts +3 -0
  37. package/dist/MemberPicker/dialog/DialogContent.js +109 -0
  38. package/dist/MemberPicker/dialog/DialogContent.js.map +1 -0
  39. package/dist/MemberPicker/dialog/MemberOption.d.ts +16 -0
  40. package/dist/MemberPicker/dialog/MemberOption.js +101 -0
  41. package/dist/MemberPicker/dialog/MemberOption.js.map +1 -0
  42. package/dist/MemberPicker/dialog/MemberPickerDialog.d.ts +11 -0
  43. package/dist/MemberPicker/dialog/MemberPickerDialog.js +11 -0
  44. package/dist/MemberPicker/dialog/MemberPickerDialog.js.map +1 -0
  45. package/dist/MemberPicker/dialog/SelectedMemberPanel.d.ts +12 -0
  46. package/dist/MemberPicker/dialog/SelectedMemberPanel.js +37 -0
  47. package/dist/MemberPicker/dialog/SelectedMemberPanel.js.map +1 -0
  48. package/dist/MemberPicker/dialog/UserCandidatePanel.d.ts +13 -0
  49. package/dist/MemberPicker/dialog/UserCandidatePanel.js +168 -0
  50. package/dist/MemberPicker/dialog/UserCandidatePanel.js.map +1 -0
  51. package/dist/MemberPicker/dialog/UserGroupCandidatePanel.d.ts +14 -0
  52. package/dist/MemberPicker/dialog/UserGroupCandidatePanel.js +134 -0
  53. package/dist/MemberPicker/dialog/UserGroupCandidatePanel.js.map +1 -0
  54. package/dist/MemberPicker/dialog/helper.d.ts +20 -0
  55. package/dist/MemberPicker/dialog/helper.js +61 -0
  56. package/dist/MemberPicker/dialog/helper.js.map +1 -0
  57. package/dist/MemberPicker/dialog/types.d.ts +41 -0
  58. package/dist/MemberPicker/dialog/types.js +7 -0
  59. package/dist/MemberPicker/dialog/types.js.map +1 -0
  60. package/dist/MemberPicker/dialog/useDialogLocale.d.ts +103 -0
  61. package/dist/MemberPicker/dialog/useDialogLocale.js +12 -0
  62. package/dist/MemberPicker/dialog/useDialogLocale.js.map +1 -0
  63. package/dist/MemberPicker/dialog/useMemberPickerDraft.d.ts +27 -0
  64. package/dist/MemberPicker/dialog/useMemberPickerDraft.js +95 -0
  65. package/dist/MemberPicker/dialog/useMemberPickerDraft.js.map +1 -0
  66. package/dist/MemberPicker/dialog/useUserGroupCandidates.d.ts +29 -0
  67. package/dist/MemberPicker/dialog/useUserGroupCandidates.js +443 -0
  68. package/dist/MemberPicker/dialog/useUserGroupCandidates.js.map +1 -0
  69. package/dist/MemberPicker/index.d.ts +2 -0
  70. package/dist/MemberPicker/index.js +61 -35
  71. package/dist/MemberPicker/index.js.map +1 -1
  72. package/dist/MemberPicker/interface.d.ts +6 -0
  73. package/dist/MemberPicker/interface.js.map +1 -1
  74. package/dist/MemberPicker/useMemberSearch.d.ts +8 -0
  75. package/dist/MemberPicker/useMemberSearch.js +51 -0
  76. package/dist/MemberPicker/useMemberSearch.js.map +1 -0
  77. package/dist/Menu/index.d.ts +6 -0
  78. package/dist/Menu/index.js +21 -9
  79. package/dist/Menu/index.js.map +1 -1
  80. package/dist/Modal/index.js +1 -1
  81. package/dist/Modal/index.js.map +1 -1
  82. package/dist/aloudata-design.css +1 -1
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.js +2 -2
  85. package/dist/locale/default.d.ts +29 -0
  86. package/dist/locale/en_US.d.ts +29 -0
  87. package/dist/locale/en_US.js +29 -0
  88. package/dist/locale/en_US.js.map +1 -1
  89. package/dist/locale/zh_CN.d.ts +29 -0
  90. package/dist/locale/zh_CN.js +29 -0
  91. package/dist/locale/zh_CN.js.map +1 -1
  92. package/package.json +2 -1
@@ -0,0 +1,168 @@
1
+ import Button_default from "../../Button/index.js";
2
+ import Checkbox from "../../Checkbox/index.js";
3
+ import InputSearch from "../../InputSearch/index.js";
4
+ import Empty from "../../Empty/index.js";
5
+ import { EUserType } from "../../ConfigProvider/getUserList.js";
6
+ import AldCustomConfigProvider from "../../ConfigProvider/index.js";
7
+ import CustomSpin from "../../Spin/index.js";
8
+ import useDialogLocale from "./useDialogLocale.js";
9
+ import { getMemberKey, isMemberLocked } from "./helper.js";
10
+ import MemberOption from "./MemberOption.js";
11
+ import SearchFeedback from "../components/SearchFeedback.js";
12
+ import { useCallback, useEffect, useRef, useState } from "react";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ //#region src/MemberPicker/dialog/UserCandidatePanel.tsx
15
+ var SEARCH_DEBOUNCE_MS = 300;
16
+ /** 用户候选继续使用设计系统既有查询语义,并在前端只接受 USER。 */
17
+ function UserCandidatePanel({ selectedByKey, onToggle, onToggleAll, lockedIds = [], filterItem, renderItem }) {
18
+ const t = useDialogLocale();
19
+ const { getUsersByKeywords, getUsersByKeywordsWithMeta, getMemberPickerUserPage } = AldCustomConfigProvider.useGetUserList();
20
+ const [keyword, setKeyword] = useState("");
21
+ const [items, setItems] = useState([]);
22
+ const [loading, setLoading] = useState(false);
23
+ const [error, setError] = useState(false);
24
+ const [hasMore, setHasMore] = useState(false);
25
+ const [truncated, setTruncated] = useState(false);
26
+ const [loadingMore, setLoadingMore] = useState(false);
27
+ const pageRef = useRef(1);
28
+ const loadedKeywordRef = useRef();
29
+ const loadingMoreRef = useRef(false);
30
+ const requestVersionRef = useRef(0);
31
+ const selectableItems = items.filter((member) => !isMemberLocked(member, lockedIds));
32
+ const selectedCount = selectableItems.filter((member) => selectedByKey.has(getMemberKey(member))).length;
33
+ const allSelected = selectableItems.length > 0 && selectedCount === selectableItems.length;
34
+ const partiallySelected = selectedCount > 0 && !allSelected;
35
+ const queryUsers = useCallback(async (searchKeyword, pageNumber = 1) => {
36
+ if (pageNumber > 1 && (loadingMoreRef.current || loadedKeywordRef.current !== searchKeyword)) return;
37
+ const version = pageNumber === 1 ? ++requestVersionRef.current : requestVersionRef.current;
38
+ if (pageNumber === 1) {
39
+ setLoading(true);
40
+ setHasMore(false);
41
+ setTruncated(false);
42
+ } else {
43
+ loadingMoreRef.current = true;
44
+ setLoadingMore(true);
45
+ }
46
+ setError(false);
47
+ try {
48
+ if (!getMemberPickerUserPage && !getUsersByKeywordsWithMeta && !getUsersByKeywords) throw new Error(t.MemberPickerDialog.missingUserSource);
49
+ const result = getMemberPickerUserPage ? await getMemberPickerUserPage({
50
+ keyword: searchKeyword,
51
+ pager: {
52
+ pageNumber,
53
+ pageSize: 100
54
+ }
55
+ }) : getUsersByKeywordsWithMeta ? await getUsersByKeywordsWithMeta(searchKeyword) : getUsersByKeywords ? {
56
+ items: await getUsersByKeywords(searchKeyword),
57
+ hasMore: false
58
+ } : {
59
+ items: [],
60
+ hasMore: false
61
+ };
62
+ if (requestVersionRef.current !== version) return;
63
+ const members = ("data" in result ? result.data : result.items).filter((member) => member.type === EUserType.USER && (filterItem ? filterItem(member) : true));
64
+ setItems((current) => pageNumber === 1 ? members : Array.from(new Map([...current, ...members].map((member) => [getMemberKey(member), member])).values()));
65
+ loadedKeywordRef.current = searchKeyword;
66
+ pageRef.current = pageNumber;
67
+ setHasMore(Boolean(getMemberPickerUserPage && result.hasMore));
68
+ setTruncated(Boolean(!getMemberPickerUserPage && result.hasMore));
69
+ } catch {
70
+ if (requestVersionRef.current === version) setError(true);
71
+ } finally {
72
+ if (requestVersionRef.current === version) {
73
+ setLoading(false);
74
+ setLoadingMore(false);
75
+ loadingMoreRef.current = false;
76
+ }
77
+ }
78
+ }, [
79
+ filterItem,
80
+ getMemberPickerUserPage,
81
+ getUsersByKeywords,
82
+ getUsersByKeywordsWithMeta,
83
+ t.MemberPickerDialog.missingUserSource
84
+ ]);
85
+ useEffect(() => {
86
+ setLoading(true);
87
+ setHasMore(false);
88
+ loadedKeywordRef.current = void 0;
89
+ loadingMoreRef.current = false;
90
+ setLoadingMore(false);
91
+ const version = requestVersionRef.current + 1;
92
+ requestVersionRef.current = version;
93
+ const timer = window.setTimeout(() => {
94
+ if (requestVersionRef.current === version) queryUsers(keyword.trim());
95
+ }, SEARCH_DEBOUNCE_MS);
96
+ return () => {
97
+ window.clearTimeout(timer);
98
+ requestVersionRef.current += 1;
99
+ };
100
+ }, [keyword, queryUsers]);
101
+ return /* @__PURE__ */ jsxs("section", {
102
+ className: "tw-flex tw-h-full tw-min-h-0 tw-flex-col",
103
+ "data-testid": "user-candidate-panel",
104
+ children: [
105
+ /* @__PURE__ */ jsx("div", {
106
+ className: "tw-shrink-0 tw-border-b tw-border-solid tw-border-border-default tw-p-sp-150",
107
+ children: /* @__PURE__ */ jsxs("div", {
108
+ className: "tw-flex tw-min-w-0 tw-flex-col tw-gap-sp-150",
109
+ children: [/* @__PURE__ */ jsx(InputSearch, {
110
+ inputMode: true,
111
+ size: "middle",
112
+ className: "tw-w-full",
113
+ debounce: false,
114
+ value: keyword,
115
+ placeholder: t.MemberPickerDialog.searchUsersPlaceholder,
116
+ onChange: setKeyword,
117
+ onSearch: setKeyword
118
+ }), /* @__PURE__ */ jsx(Checkbox, {
119
+ size: "small",
120
+ className: "tw-self-start",
121
+ checked: allSelected,
122
+ indeterminate: partiallySelected,
123
+ disabled: loading || error || selectableItems.length === 0,
124
+ onChange: (event) => onToggleAll(selectableItems, event.target.checked),
125
+ children: allSelected ? t.MemberPickerDialog.deselectCurrent(items.length) : t.MemberPickerDialog.selectCurrent(items.length)
126
+ })]
127
+ })
128
+ }),
129
+ /* @__PURE__ */ jsx(SearchFeedback, {
130
+ hasMore: truncated,
131
+ retry: () => queryUsers(keyword.trim())
132
+ }),
133
+ /* @__PURE__ */ jsxs("div", {
134
+ className: "tw-min-h-0 tw-flex-1 tw-overflow-auto tw-py-sp-100",
135
+ children: [
136
+ loading ? /* @__PURE__ */ jsx(CustomSpin, {}) : null,
137
+ error ? /* @__PURE__ */ jsxs("div", {
138
+ className: "tw-flex tw-h-full tw-flex-col tw-items-center tw-justify-center tw-gap-2",
139
+ children: [/* @__PURE__ */ jsx("span", { children: t.MemberPickerDialog.loadFailed }), /* @__PURE__ */ jsx(Button_default, {
140
+ type: "link",
141
+ onClick: () => queryUsers(keyword.trim()),
142
+ children: t.MemberPickerDialog.retry
143
+ })]
144
+ }) : null,
145
+ !loading && !error && !items.length ? /* @__PURE__ */ jsx(Empty, { description: t.MemberPickerDialog.emptyCandidates }) : null,
146
+ !loading && !error ? items.map((member) => /* @__PURE__ */ jsx(MemberOption, {
147
+ member,
148
+ selected: selectedByKey.has(getMemberKey(member)),
149
+ locked: isMemberLocked(member, lockedIds),
150
+ onToggle,
151
+ renderItem,
152
+ searchValue: keyword
153
+ }, getMemberKey(member))) : null,
154
+ hasMore && /* @__PURE__ */ jsx(Button_default, {
155
+ type: "link",
156
+ loading: loadingMore,
157
+ onClick: () => queryUsers(keyword.trim(), pageRef.current + 1),
158
+ children: t.MemberPickerDialog.loadMore
159
+ })
160
+ ]
161
+ })
162
+ ]
163
+ });
164
+ }
165
+ //#endregion
166
+ export { UserCandidatePanel as default };
167
+
168
+ //# sourceMappingURL=UserCandidatePanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserCandidatePanel.js","names":[],"sources":["../../../src/MemberPicker/dialog/UserCandidatePanel.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport Button from '../../Button';\nimport Checkbox from '../../Checkbox';\nimport ConfigProvider from '../../ConfigProvider';\nimport { EUserType } from '../../ConfigProvider/getUserList';\nimport Empty from '../../Empty';\nimport InputSearch from '../../InputSearch';\nimport Spin from '../../Spin';\nimport type { IMemberPickerProps as MemberPickerProps } from '../interface';\nimport SearchFeedback from '../components/SearchFeedback';\nimport useDialogLocale from './useDialogLocale';\nimport { getMemberKey, isMemberLocked } from './helper';\nimport MemberOption from './MemberOption';\nimport type { TMember, TMemberKey } from './types';\n\nconst SEARCH_DEBOUNCE_MS = 300;\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/** 用户候选继续使用设计系统既有查询语义,并在前端只接受 USER。 */\nexport default function UserCandidatePanel({\n selectedByKey,\n onToggle,\n onToggleAll,\n lockedIds = [],\n filterItem,\n renderItem,\n}: IProps) {\n const t = useDialogLocale();\n const {\n getUsersByKeywords,\n getUsersByKeywordsWithMeta,\n getMemberPickerUserPage,\n } = ConfigProvider.useGetUserList();\n const [keyword, setKeyword] = useState('');\n const [items, setItems] = useState<TMember[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(false);\n const [hasMore, setHasMore] = useState(false);\n const [truncated, setTruncated] = useState(false);\n const [loadingMore, setLoadingMore] = useState(false);\n const pageRef = useRef(1);\n const loadedKeywordRef = useRef<string>();\n const loadingMoreRef = useRef(false);\n const requestVersionRef = useRef(0);\n const selectableItems = items.filter(\n (member) => !isMemberLocked(member, lockedIds),\n );\n const selectedCount = selectableItems.filter((member) =>\n selectedByKey.has(getMemberKey(member)),\n ).length;\n const allSelected =\n selectableItems.length > 0 && selectedCount === selectableItems.length;\n const partiallySelected = selectedCount > 0 && !allSelected;\n\n const queryUsers = useCallback(\n async (searchKeyword: string, pageNumber = 1) => {\n // 只能追加已成功加载首屏的关键词,避免换词防抖期间使用旧页码。\n if (\n pageNumber > 1 &&\n (loadingMoreRef.current || loadedKeywordRef.current !== searchKeyword)\n )\n return;\n const version =\n pageNumber === 1\n ? ++requestVersionRef.current\n : requestVersionRef.current;\n if (pageNumber === 1) {\n setLoading(true);\n setHasMore(false);\n setTruncated(false);\n } else {\n loadingMoreRef.current = true;\n setLoadingMore(true);\n }\n setError(false);\n try {\n if (\n !getMemberPickerUserPage &&\n !getUsersByKeywordsWithMeta &&\n !getUsersByKeywords\n )\n throw new Error(t.MemberPickerDialog.missingUserSource);\n const result = getMemberPickerUserPage\n ? await getMemberPickerUserPage({\n keyword: searchKeyword,\n pager: { pageNumber, pageSize: 100 },\n })\n : getUsersByKeywordsWithMeta\n ? await getUsersByKeywordsWithMeta(searchKeyword)\n : getUsersByKeywords\n ? { items: await getUsersByKeywords(searchKeyword), hasMore: false }\n : { items: [], hasMore: false };\n if (requestVersionRef.current !== version) return;\n const members = ('data' in result ? result.data : result.items).filter(\n (member) =>\n member.type === EUserType.USER &&\n (filterItem ? filterItem(member) : true),\n );\n setItems((current) =>\n pageNumber === 1\n ? members\n : Array.from(\n new Map(\n [...current, ...members].map((member) => [\n getMemberKey(member),\n member,\n ]),\n ).values(),\n ),\n );\n loadedKeywordRef.current = searchKeyword;\n pageRef.current = pageNumber;\n setHasMore(Boolean(getMemberPickerUserPage && result.hasMore));\n setTruncated(Boolean(!getMemberPickerUserPage && result.hasMore));\n } catch {\n if (requestVersionRef.current === version) setError(true);\n } finally {\n if (requestVersionRef.current === version) {\n setLoading(false);\n setLoadingMore(false);\n loadingMoreRef.current = false;\n }\n }\n },\n [\n filterItem,\n getMemberPickerUserPage,\n getUsersByKeywords,\n getUsersByKeywordsWithMeta,\n t.MemberPickerDialog.missingUserSource,\n ],\n );\n\n useEffect(() => {\n // 输入改变立即隐藏旧候选和分页入口,防抖只延迟请求,不延迟失效旧结果。\n setLoading(true);\n setHasMore(false);\n loadedKeywordRef.current = undefined;\n loadingMoreRef.current = false;\n setLoadingMore(false);\n const version = requestVersionRef.current + 1;\n requestVersionRef.current = version;\n const timer = window.setTimeout(() => {\n if (requestVersionRef.current === version) {\n queryUsers(keyword.trim());\n }\n }, SEARCH_DEBOUNCE_MS);\n return () => {\n window.clearTimeout(timer);\n requestVersionRef.current += 1;\n };\n }, [keyword, queryUsers]);\n\n return (\n <section\n className=\"tw-flex tw-h-full tw-min-h-0 tw-flex-col\"\n data-testid=\"user-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 <InputSearch\n inputMode\n size=\"middle\"\n className=\"tw-w-full\"\n debounce={false}\n value={keyword}\n placeholder={t.MemberPickerDialog.searchUsersPlaceholder}\n onChange={setKeyword}\n onSearch={setKeyword}\n />\n <Checkbox\n size=\"small\"\n className=\"tw-self-start\"\n checked={allSelected}\n indeterminate={partiallySelected}\n disabled={loading || error || selectableItems.length === 0}\n onChange={(event) =>\n onToggleAll(selectableItems, event.target.checked)\n }\n >\n {allSelected\n ? t.MemberPickerDialog.deselectCurrent(items.length)\n : t.MemberPickerDialog.selectCurrent(items.length)}\n </Checkbox>\n </div>\n </div>\n <SearchFeedback\n hasMore={truncated}\n retry={() => queryUsers(keyword.trim())}\n />\n <div className=\"tw-min-h-0 tw-flex-1 tw-overflow-auto tw-py-sp-100\">\n {loading ? <Spin /> : null}\n {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={() => queryUsers(keyword.trim())}>\n {t.MemberPickerDialog.retry}\n </Button>\n </div>\n ) : null}\n {!loading && !error && !items.length ? (\n <Empty description={t.MemberPickerDialog.emptyCandidates} />\n ) : null}\n {!loading && !error\n ? items.map((member) => (\n <MemberOption\n key={getMemberKey(member)}\n member={member}\n selected={selectedByKey.has(getMemberKey(member))}\n locked={isMemberLocked(member, lockedIds)}\n onToggle={onToggle}\n renderItem={renderItem}\n searchValue={keyword}\n />\n ))\n : null}\n {hasMore && (\n <Button\n type=\"link\"\n loading={loadingMore}\n onClick={() => queryUsers(keyword.trim(), pageRef.current + 1)}\n >\n {t.MemberPickerDialog.loadMore}\n </Button>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
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
+ canEnterGroup?: MemberPickerProps['canEnterGroup'];
10
+ renderItem?: MemberPickerProps['renderItem'];
11
+ }
12
+ /** 用户组树与跨层搜索共用选择事实源,但互不重置彼此的浏览状态。 */
13
+ export default function UserGroupCandidatePanel({ selectedByKey, onToggle, onToggleAll, lockedIds, filterItem, canEnterGroup, renderItem, }: IProps): import("react/jsx-runtime").JSX.Element;
14
+ 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, canEnterGroup, 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 || canEnterGroup?.(group) === false ? 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 canEnterGroup?: MemberPickerProps['canEnterGroup'];\n renderItem?: MemberPickerProps['renderItem'];\n}\n\n/** 用户组树与跨层搜索共用选择事实源,但互不重置彼此的浏览状态。 */\nexport default function UserGroupCandidatePanel({\n selectedByKey,\n onToggle,\n onToggleAll,\n lockedIds = [],\n filterItem,\n canEnterGroup,\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 || canEnterGroup?.(group) === false\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,7 @@
1
+ //#region src/MemberPicker/dialog/types.ts
2
+ /** 根层没有 parentGroupId,使用显式 key 避免 Map 中混用 undefined。 */
3
+ var ROOT_GROUP_CACHE_KEY = "__ROOT_GROUP__";
4
+ //#endregion
5
+ export { ROOT_GROUP_CACHE_KEY };
6
+
7
+ //# sourceMappingURL=types.js.map
@@ -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"}