Skip to content

Commit 97b4259

Browse files
committed
feat(catalogue): add custom overlay, form.error msg and drag style
1 parent 99e2000 commit 97b4259

File tree

7 files changed

+187
-93
lines changed

7 files changed

+187
-93
lines changed

src/catalogue/components/catalogue.tsx

Lines changed: 37 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import React, { useMemo } from 'react';
2-
import { Dropdown, Form, Input, Menu, Spin } from 'antd';
1+
import React from 'react';
2+
import { Dropdown, DropdownProps, Form, Input, Spin } from 'antd';
33
import { DataNode } from 'antd/lib/tree';
4-
import { EllipsisText, Empty } from 'dt-react-component';
5-
import BlockHeader, { IBlockHeaderProps } from 'dt-react-component/blockHeader';
4+
import { BlockHeader, EllipsisText, Empty } from 'dt-react-component';
5+
import { IBlockHeaderProps } from 'dt-react-component/blockHeader';
66

77
import { InputStatus, ITreeNode, useTreeData } from '../useTreeData';
8-
import { CatalogIcon, DeleteIcon, DragIcon, EditIcon, EllipsisIcon, PlusCircleIcon } from './icon';
8+
import { CatalogIcon, DragIcon, EllipsisIcon } from './icon';
99
import CatalogueTree, { ICatalogueTree } from './tree';
1010

11-
interface ICatalogue
11+
export interface ICatalogue
1212
extends Pick<IBlockHeaderProps, 'tooltip' | 'addonAfter' | 'addonBefore' | 'title'>,
13-
Pick<ReturnType<typeof useTreeData>, 'onChange'>,
1413
ICatalogueTree {
1514
showSearch?: boolean;
1615
edit?: boolean;
1716
placeholder?: string;
1817
loading?: boolean;
18+
onChange?: ReturnType<typeof useTreeData>['onChange'];
19+
overlay?: (item: ITreeNode) => DropdownProps['overlay'];
1920
onSearch?: (value: string) => void;
20-
onSave?: (data: ITreeNode, value: string) => void;
21-
onDelete?: (data: ITreeNode) => void;
21+
onSave?: (data: ITreeNode, value: string) => Promise<string | void>;
2222
}
2323

2424
const Catalogue = ({
@@ -32,11 +32,11 @@ const Catalogue = ({
3232
loading = false,
3333
treeData,
3434
draggable,
35+
overlay,
3536
onChange,
3637
onSearch,
3738
onExpand,
3839
onSave,
39-
onDelete,
4040
...rest
4141
}: ICatalogue) => {
4242
const [form] = Form.useForm();
@@ -90,12 +90,13 @@ const Catalogue = ({
9090
};
9191

9292
const renderTree = () => {
93+
const treeDataWithTitle = loopTree(treeData);
9394
if (!treeDataWithTitle.length) return <Empty style={{ marginTop: 130 }} />;
9495
return (
9596
<div className="dt-catalogue__tree">
9697
<Spin spinning={loading}>
9798
<CatalogueTree
98-
treeData={treeDataWithTitle}
99+
treeData={loopTree(treeData)}
99100
draggable={draggable ? { icon: false } : false}
100101
onExpand={onExpand}
101102
{...rest}
@@ -125,22 +126,30 @@ const Catalogue = ({
125126
return result;
126127
};
127128
const parentItem = findAppendParents(treeData, item);
128-
return parentItem && onSave?.({ ...parentItem, type: InputStatus.Append }, value);
129+
return (
130+
parentItem &&
131+
onSave?.({ ...parentItem, type: InputStatus.Append }, value).then((msg) => {
132+
form.setFields([{ name: 'catalog_input', errors: msg ? [msg] : [] }]);
133+
})
134+
);
129135
}
130-
onSave?.(item, value);
136+
onSave?.(item, value).then((msg) => {
137+
form.setFields([{ name: 'catalog_input', errors: msg ? [msg] : [] }]);
138+
});
131139
};
132140

133141
const renderInput = (item: DataNode) => {
134142
return (
135143
<div className="tree__title--input">
136-
<Form form={form}>
137-
<Form.Item>
144+
<Form form={form} preserve={false}>
145+
<Form.Item name="catalog_input">
138146
<Input
139147
defaultValue={item?.title as string}
140148
size="small"
141149
placeholder={`请输入${title}名称`}
142150
maxLength={100}
143151
autoFocus
152+
onFocus={() => form.setFields([{ name: 'catalog_input', errors: [] }])}
144153
onClick={(e) => e.stopPropagation()}
145154
onBlur={({ target }) => handleInputSubmit(item, target.value)}
146155
onPressEnter={({ target }) =>
@@ -170,68 +179,31 @@ const Catalogue = ({
170179
};
171180

172181
const renderNodeHover = (item: ITreeNode) => {
173-
const menu = (
174-
<Menu
175-
className="tree__title--menu"
176-
onClick={({ domEvent }) => {
177-
domEvent.stopPropagation();
178-
}}
179-
>
180-
<Menu.Item
181-
key="add"
182-
className="title__menu--item"
183-
disabled={!item.addable}
184-
onClick={() => item.addable && onChange?.(item, InputStatus.Append)}
185-
>
186-
<PlusCircleIcon />
187-
<span>新建目录</span>
188-
</Menu.Item>
189-
<Menu.Item
190-
key="edit"
191-
className="title__menu--item"
192-
disabled={!item.editable}
193-
onClick={() => item.editable && onChange?.(item, InputStatus.Edit)}
194-
>
195-
<EditIcon />
196-
<span>编辑</span>
197-
</Menu.Item>
198-
<Menu.Item
199-
key="delete"
200-
className="title__menu--item"
201-
disabled={!item.deletable}
202-
onClick={() => item.deletable && onDelete?.(item)}
203-
>
204-
<DeleteIcon />
205-
<span>删除</span>
206-
</Menu.Item>
207-
</Menu>
208-
);
209182
return (
210183
<div
211184
className="tree__title--operation"
212185
onMouseDown={(e) => {
213186
e.stopPropagation();
214187
}}
215188
>
216-
<Dropdown
217-
overlay={menu}
218-
trigger={['click']}
219-
placement="bottomRight"
220-
arrow
221-
destroyPopupOnHide
222-
getPopupContainer={(triggerNode) => triggerNode.parentElement as HTMLElement}
223-
>
224-
<EllipsisIcon onClick={(e) => e.stopPropagation()} />
225-
</Dropdown>
189+
{overlay && (
190+
<Dropdown
191+
overlay={overlay(item)}
192+
placement="bottomRight"
193+
arrow
194+
destroyPopupOnHide
195+
getPopupContainer={(triggerNode) =>
196+
triggerNode.parentElement as HTMLElement
197+
}
198+
>
199+
<EllipsisIcon onClick={(e) => e.stopPropagation()} />
200+
</Dropdown>
201+
)}
226202
{draggable && <DragIcon />}
227203
</div>
228204
);
229205
};
230206

231-
const treeDataWithTitle = useMemo(() => {
232-
return loopTree(treeData);
233-
}, [treeData]);
234-
235207
return (
236208
<div className="dt-catalogue">
237209
<div className="dt-catalogue__header">

src/catalogue/demos/basic.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useEffect } from 'react';
2+
import { Catalogue } from 'dt-react-component';
23

34
import { useTreeData } from '../useTreeData';
4-
import Catalogue from '..';
55

66
const DEFAULT_DATA = [
77
{

src/catalogue/demos/config.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { useEffect } from 'react';
2+
import { Menu } from 'antd';
23
import { TreeProps } from 'antd/lib/tree';
4+
import { Catalogue } from 'dt-react-component';
35
import { cloneDeep } from 'lodash';
46
import shortid from 'shortid';
57

6-
import { PlusSquareIcon } from '../components/icon';
8+
import { DeleteIcon, EditIcon, PlusCircleIcon, PlusSquareIcon } from '../components/icon';
79
import { InputStatus, ITreeNode, useTreeData } from '../useTreeData';
8-
import Catalogue from '..';
910

1011
const DEFAULT_DATA: ITreeNode[] = [
1112
{
@@ -70,7 +71,7 @@ export default () => {
7071
return null;
7172
};
7273

73-
const handleSave = (data: ITreeNode, value: string) => {
74+
const handleSave = async (data: ITreeNode, value: string) => {
7475
const newData = cloneDeep(treeData.data);
7576
if (data.type === InputStatus.Add) {
7677
newData.push({
@@ -201,13 +202,50 @@ export default () => {
201202
title="标签目录"
202203
showSearch
203204
draggable
205+
overlay={(item) => (
206+
<Menu
207+
onClick={({ domEvent }) => {
208+
domEvent.stopPropagation();
209+
}}
210+
>
211+
<Menu.Item
212+
key="add"
213+
disabled={!item.addable}
214+
onClick={() =>
215+
item.addable && treeData.onChange(item, InputStatus.Append)
216+
}
217+
>
218+
<PlusCircleIcon />
219+
<span>新建目录</span>
220+
</Menu.Item>
221+
<Menu.Item
222+
key="edit"
223+
className="title__menu--item"
224+
disabled={!item.editable}
225+
onClick={() =>
226+
item.editable && treeData.onChange(item, InputStatus.Edit)
227+
}
228+
>
229+
<EditIcon />
230+
<span>编辑</span>
231+
</Menu.Item>
232+
<Menu.Item
233+
key="delete"
234+
className="title__menu--item"
235+
disabled={!item.deletable}
236+
onClick={() => item.deletable && handleDelete(item)}
237+
>
238+
<DeleteIcon />
239+
<span>删除</span>
240+
</Menu.Item>
241+
</Menu>
242+
)}
204243
treeData={treeData.data}
205244
expandedKeys={treeData.expandedKeys}
206245
onExpand={treeData.setExpandedKeys}
207246
onDragEnter={({ expandedKeys }) => treeData.setExpandedKeys(expandedKeys)}
208247
onChange={treeData.onChange}
209248
onSave={handleSave}
210-
onDelete={handleDelete}
211249
onDrop={handleDrop}
212250
/>
213251
</div>

src/catalogue/demos/drag.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { useEffect } from 'react';
2+
import { Menu } from 'antd';
23
import { TreeProps } from 'antd/lib/tree';
4+
import { Catalogue } from 'dt-react-component';
35
import { cloneDeep } from 'lodash';
46
import shortid from 'shortid';
57

6-
import { PlusSquareIcon } from '../components/icon';
8+
import { DeleteIcon, EditIcon, PlusCircleIcon, PlusSquareIcon } from '../components/icon';
79
import { InputStatus, ITreeNode, useTreeData } from '../useTreeData';
8-
import Catalogue from '..';
910

1011
const DEFAULT_DATA = [
1112
{
@@ -67,7 +68,7 @@ export default () => {
6768
return null;
6869
};
6970

70-
const handleSave = (data: ITreeNode, value: string) => {
71+
const handleSave = async (data: ITreeNode, value: string) => {
7172
const newData = cloneDeep(treeData.data);
7273
if (data.type === InputStatus.Add) {
7374
newData.push({
@@ -198,13 +199,50 @@ export default () => {
198199
title="标签目录"
199200
showSearch
200201
draggable
202+
overlay={(item) => (
203+
<Menu
204+
onClick={({ domEvent }) => {
205+
domEvent.stopPropagation();
206+
}}
207+
>
208+
<Menu.Item
209+
key="add"
210+
disabled={!item.addable}
211+
onClick={() =>
212+
item.addable && treeData.onChange(item, InputStatus.Append)
213+
}
214+
>
215+
<PlusCircleIcon />
216+
<span>新建目录</span>
217+
</Menu.Item>
218+
<Menu.Item
219+
key="edit"
220+
className="title__menu--item"
221+
disabled={!item.editable}
222+
onClick={() =>
223+
item.editable && treeData.onChange(item, InputStatus.Edit)
224+
}
225+
>
226+
<EditIcon />
227+
<span>编辑</span>
228+
</Menu.Item>
229+
<Menu.Item
230+
key="delete"
231+
className="title__menu--item"
232+
disabled={!item.deletable}
233+
onClick={() => item.deletable && handleDelete(item)}
234+
>
235+
<DeleteIcon />
236+
<span>删除</span>
237+
</Menu.Item>
238+
</Menu>
239+
)}
201240
treeData={treeData.data}
202241
expandedKeys={treeData.expandedKeys}
203242
onExpand={treeData.setExpandedKeys}
204243
onDragEnter={({ expandedKeys }) => treeData.setExpandedKeys(expandedKeys)}
205244
onChange={treeData.onChange}
206245
onSave={handleSave}
207-
onDelete={handleDelete}
208246
onDrop={handleDrop}
209247
/>
210248
</div>

0 commit comments

Comments
 (0)