@fe-free/core 2.8.0 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @fe-free/core
2
2
 
3
+ ## 2.8.2
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: tree
8
+ - @fe-free/tool@2.8.2
9
+
10
+ ## 2.8.1
11
+
12
+ ### Patch Changes
13
+
14
+ - fix: tree
15
+ - @fe-free/tool@2.8.1
16
+
3
17
  ## 2.8.0
4
18
 
5
19
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fe-free/core",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
4
4
  "description": "",
5
5
  "main": "./src/index.ts",
6
6
  "author": "",
@@ -41,7 +41,7 @@
41
41
  "remark-gfm": "^4.0.1",
42
42
  "vanilla-jsoneditor": "^0.23.1",
43
43
  "zustand": "^4.5.4",
44
- "@fe-free/tool": "2.8.0"
44
+ "@fe-free/tool": "2.8.2"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@ant-design/pro-components": "2.8.9",
@@ -92,8 +92,30 @@ export const Default: Story = {
92
92
  key: '4',
93
93
  children: [],
94
94
  },
95
+ {
96
+ title: 'more operateIsDisabled',
97
+ key: '5',
98
+ children: [],
99
+ },
100
+ {
101
+ title: 'more operateIsHidden',
102
+ key: '6',
103
+ children: [],
104
+ },
95
105
  ],
96
106
  },
107
+ createProps: {
108
+ operateIsDisabled: (nodeData) => nodeData?.key === '5',
109
+ operateIsHidden: (nodeData) => nodeData?.key === '6',
110
+ },
111
+ updateProps: {
112
+ operateIsDisabled: (nodeData) => nodeData.key === '5',
113
+ operateIsHidden: (nodeData) => nodeData.key === '6',
114
+ },
115
+ deleteProps: {
116
+ operateIsDisabled: (nodeData) => nodeData.key === '5',
117
+ operateIsHidden: (nodeData) => nodeData.key === '6',
118
+ },
97
119
  },
98
120
  };
99
121
 
@@ -16,6 +16,20 @@ interface FileTreeProps<D extends DataNode> extends TreeProps<D> {
16
16
  requestCreateByValues?: (values: { key?: string; title: string }) => Promise<false | void>;
17
17
  requestUpdateByValues?: (values: { key: string; title: string }) => Promise<false | void>;
18
18
  requestDeleteByRecord?: (values: { key: string }) => Promise<void>;
19
+ /** 注意,没法控制 title 区域的添加(由 actions 来控制) */
20
+ createProps?: {
21
+ operateIsDisabled?: (nodeData: D) => boolean;
22
+
23
+ operateIsHidden?: (nodeData: D) => boolean;
24
+ };
25
+ updateProps?: {
26
+ operateIsDisabled?: (nodeData: D) => boolean;
27
+ operateIsHidden?: (nodeData: D) => boolean;
28
+ };
29
+ deleteProps?: {
30
+ operateIsDisabled?: (nodeData: D) => boolean;
31
+ operateIsHidden?: (nodeData: D) => boolean;
32
+ };
19
33
  }
20
34
 
21
35
  function Detail<D extends DataNode>({
@@ -77,44 +91,69 @@ function More({
77
91
  requestUpdateByValues,
78
92
  requestDeleteByRecord,
79
93
  requestCreateByValues,
94
+ createProps,
95
+ updateProps,
96
+ deleteProps,
80
97
  }) {
98
+ const isCreateDisabled = createProps?.operateIsDisabled?.(nodeData);
99
+ const isCreateHidden = createProps?.operateIsHidden?.(nodeData);
100
+ const isUpdateDisabled = updateProps?.operateIsDisabled?.(nodeData);
101
+ const isUpdateHidden = updateProps?.operateIsHidden?.(nodeData);
102
+ const isDeleteDisabled = deleteProps?.operateIsDisabled?.(nodeData);
103
+ const isDeleteHidden = deleteProps?.operateIsHidden?.(nodeData);
104
+
105
+ const menuItems = [
106
+ actions?.includes('create') &&
107
+ !isCreateHidden && {
108
+ label: isCreateDisabled ? (
109
+ <div className="cursor-not-allowed text-desc">新建子目录</div>
110
+ ) : (
111
+ <Detail
112
+ action="create"
113
+ nodeData={{ key: nodeData.key }}
114
+ requestCreateByValues={(values) => requestCreateByValues?.({ ...values })}
115
+ trigger={<div>新建子目录</div>}
116
+ />
117
+ ),
118
+ key: 'create',
119
+ },
120
+ actions?.includes('update') &&
121
+ !isUpdateHidden && {
122
+ label: isUpdateDisabled ? (
123
+ <div className="cursor-not-allowed text-desc">编辑</div>
124
+ ) : (
125
+ <Detail
126
+ action="update"
127
+ nodeData={nodeData}
128
+ requestUpdateByValues={(values) => requestUpdateByValues?.({ ...values })}
129
+ trigger={<div>编辑</div>}
130
+ />
131
+ ),
132
+ key: 'update',
133
+ },
134
+ actions?.includes('delete') &&
135
+ !isDeleteHidden && {
136
+ label: isDeleteDisabled ? (
137
+ <div className="cursor-not-allowed text-desc">删除</div>
138
+ ) : (
139
+ <OperateDelete
140
+ name={nodeData.title}
141
+ onDelete={() => requestDeleteByRecord?.({ key: nodeData.key })}
142
+ />
143
+ ),
144
+ key: 'delete',
145
+ },
146
+ ].filter(Boolean);
147
+
148
+ if (menuItems.length === 0) {
149
+ return null;
150
+ }
151
+
81
152
  return (
82
153
  <Dropdown
83
154
  placement="bottomRight"
84
155
  menu={{
85
- items: [
86
- actions?.includes('create') && {
87
- label: (
88
- <Detail
89
- action="create"
90
- nodeData={{ key: nodeData.key }}
91
- requestCreateByValues={(values) => requestCreateByValues?.({ ...values })}
92
- trigger={<div>新建子目录</div>}
93
- />
94
- ),
95
- key: 'create',
96
- },
97
- actions?.includes('update') && {
98
- label: (
99
- <Detail
100
- action="update"
101
- nodeData={nodeData}
102
- requestUpdateByValues={(values) => requestUpdateByValues?.({ ...values })}
103
- trigger={<div>编辑</div>}
104
- />
105
- ),
106
- key: 'update',
107
- },
108
- actions?.includes('delete') && {
109
- label: (
110
- <OperateDelete
111
- name={nodeData.title}
112
- onDelete={() => requestDeleteByRecord?.({ key: nodeData.key })}
113
- />
114
- ),
115
- key: 'delete',
116
- },
117
- ].filter(Boolean),
156
+ items: menuItems,
118
157
  }}
119
158
  >
120
159
  <div onClick={(e) => e.preventDefault()}>
@@ -141,14 +180,16 @@ function FileTree<D extends DataNode>(props: FileTreeProps<D>) {
141
180
 
142
181
  const titleRender = useCallback(
143
182
  (nodeData) => {
144
- console.log(nodeData);
145
183
  const hasMore = props.actions?.includes('update') || props.actions?.includes('delete');
146
184
  return (
147
185
  <div className="group flex gap-1">
148
186
  {nodeData.children ? (
149
187
  <FileCard.FileIcon isDirectory className="text-base" />
150
188
  ) : (
151
- <FileCard.FileIcon name={nodeData.title} className="text-base" />
189
+ <FileCard.FileIcon
190
+ name={nodeData.originData?.title || nodeData.title}
191
+ className="text-base"
192
+ />
152
193
  )}
153
194
  <div className="flex-1 truncate">{nodeData.title}</div>
154
195
  <div className={classNames('text-desc', { 'group-hover:hidden': hasMore })}>
@@ -162,6 +203,9 @@ function FileTree<D extends DataNode>(props: FileTreeProps<D>) {
162
203
  requestCreateByValues={props.requestCreateByValues}
163
204
  requestUpdateByValues={props.requestUpdateByValues}
164
205
  requestDeleteByRecord={props.requestDeleteByRecord}
206
+ createProps={props.createProps}
207
+ updateProps={props.updateProps}
208
+ deleteProps={props.deleteProps}
165
209
  />
166
210
  </div>
167
211
  )}
@@ -173,6 +217,9 @@ function FileTree<D extends DataNode>(props: FileTreeProps<D>) {
173
217
  props.requestCreateByValues,
174
218
  props.requestDeleteByRecord,
175
219
  props.requestUpdateByValues,
220
+ props.createProps,
221
+ props.updateProps,
222
+ props.deleteProps,
176
223
  ],
177
224
  );
178
225
 
package/src/tree/tree.tsx CHANGED
@@ -30,10 +30,10 @@ function useHighLightTreeData({ treeData, search }) {
30
30
 
31
31
  const loop = (data) => {
32
32
  return data.map((item) => {
33
- const strTitle = item.title as string;
34
- const index = strTitle.indexOf(search);
35
- const beforeStr = strTitle.substring(0, index);
36
- const afterStr = strTitle.slice(index + search.length);
33
+ const originStrTitle = item.title as string;
34
+ const index = originStrTitle.indexOf(search);
35
+ const beforeStr = originStrTitle.substring(0, index);
36
+ const afterStr = originStrTitle.slice(index + search.length);
37
37
  const title =
38
38
  index > -1 ? (
39
39
  <span key={item.key}>
@@ -42,7 +42,7 @@ function useHighLightTreeData({ treeData, search }) {
42
42
  {afterStr}
43
43
  </span>
44
44
  ) : (
45
- <span key={item.key}>{strTitle}</span>
45
+ <span key={item.key}>{originStrTitle}</span>
46
46
  );
47
47
 
48
48
  if (item.children) {
@@ -52,6 +52,7 @@ function useHighLightTreeData({ treeData, search }) {
52
52
  return {
53
53
  ...item,
54
54
  title,
55
+ originData: item,
55
56
  };
56
57
  });
57
58
  };
@@ -76,21 +77,23 @@ function useFilterTreeData({ treeData, search }) {
76
77
 
77
78
  // 递归过滤树形数据
78
79
  const filterTree = (nodes) => {
80
+ // 返回自己。 而非 [] undefined,因为要保留原数据格式。
79
81
  if (!nodes || nodes.length === 0) {
80
- return [];
82
+ return nodes;
81
83
  }
82
84
 
83
85
  return nodes
84
86
  .map((node) => {
85
- const children = node.children ? filterTree(node.children) : [];
86
87
  const isMatch = isNodeMatch(node);
87
- const hasMatchingChildren = children.length > 0;
88
+
89
+ const children = filterTree(node.children);
90
+ const hasMatchingChildren = children?.length > 0;
88
91
 
89
92
  // 如果当前节点匹配或者有匹配的子节点,则保留该节点
90
93
  if (isMatch || hasMatchingChildren) {
91
94
  return {
92
95
  ...node,
93
- children: hasMatchingChildren ? children : undefined,
96
+ children,
94
97
  };
95
98
  }
96
99
 
@@ -105,7 +108,11 @@ function useFilterTreeData({ treeData, search }) {
105
108
 
106
109
  function useIsAllLeaf(treeData?: DataNode[]) {
107
110
  return useMemo(() => {
108
- return treeData?.every((item) => item.children === undefined) || true;
111
+ if (treeData) {
112
+ return !treeData.find((item) => item.children);
113
+ }
114
+
115
+ return true;
109
116
  }, [treeData]);
110
117
  }
111
118