Skip to content

Commit

Permalink
feat: conetxtMenu add
Browse files Browse the repository at this point in the history
conetxtMenu add
  • Loading branch information
zhangtengjin committed Dec 1, 2020
1 parent 629e343 commit d3f334a
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 188 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
node_modules
dist
coverage
.DS_Store
.DS_Store
storybook-static
188 changes: 177 additions & 11 deletions src/components/tree/index.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,188 @@
import * as React from 'react';
import RcTree from 'rc-tree';
import { memo, useEffect, useState } from 'react';
import Tree, { TreeNode } from 'rc-tree';
import { TreeProps } from 'rc-tree/lib/Tree';
import './style.scss';
import { IMenuItem } from 'mo/components/menu';
import { Icon } from 'mo/components/icon';
import { Menu } from 'mo/components/menu';
import { useContextMenu } from 'mo/components/contextMenu';
import { prefixClaName, classNames } from 'mo/common/className';
import { HTMLElementType } from 'mo/common/dom';
import './style.scss';

export function getElementByCustomAttr(id: string): HTMLElementType {
return document.querySelector(`div[data-id=${id}]`)
};
export function generateTreeId(id?: string): string {
return `mo_treeNode_${id}`
}

export interface ITreeNodeItem {
key?: string | number;
title?: React.ReactNode | string;
type?: 'folder' | 'file';
contextMenu?: IMenuItem[];
children?: ITreeNodeItem[];
readonly id?: string;
icon?: string | React.ReactNode;
className?: string;
}
export interface ITreeProps extends TreeProps {
data: ITreeNodeItem[];
className?: string;
}
const TreeView: React.FunctionComponent<ITreeProps> = (props: ITreeProps) => {
const { className, data, ...others } = props;
const [treeData, setTreeData] = useState<ITreeNodeItem[]>(data);
const [activeData, setActiveData] = useState<ITreeNodeItem>({});

export interface ITree {}
const getContextMenuList = (type?: 'folder' | 'file') => {
let contextMenu: IMenuItem[] = [];
if (type === 'folder') {
contextMenu = [
{
id: 'newFile',
name: 'New File',
onClick: (e, active) => { console.log('New File Click', active) }
},
{
id: 'newFolder',
name: 'New Folder'
},
{
id: 'rename',
name: 'Rename'
},
{
id: 'delete',
name: 'Delete'
}
]
} else if (type === 'file') {
contextMenu = [
{
id: 'openToSide',
name: 'Open to the side'
},
{
id: 'rename',
name: 'Rename'
},
{
id: 'delete',
name: 'Delete'
}
]
}
return contextMenu
}
useEffect(() => {
const { contextMenu, id, type } = activeData;
const moContextMenu: IMenuItem[] = contextMenu || getContextMenuList(type);
const renderContextMenu = () => <Menu data={moContextMenu} />;
let contextViewMenu;
if (moContextMenu && moContextMenu.length > 0) {
contextViewMenu = useContextMenu({
anchor: getElementByCustomAttr(`${generateTreeId(id)}`),
render: renderContextMenu,
});
}
return function cleanup() {
console.log('cleanup')
contextViewMenu?.dispose();
};
}, [data, activeData]);

interface ITreeProps extends TreeProps {}
const onDrop = (info) => {
console.log(info);
const dropKey = info.node.props.eventKey;
const dragKey = info.dragNode.props.eventKey;
const dropPos = info.node.props.pos.split('-');
const dropPosition =
info.dropPosition - Number(dropPos[dropPos.length - 1]);

export const Tree: React.FunctionComponent<ITreeProps> = (
props: ITreeProps
) => {
const { className, ...others } = props;
const loopTree = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
return callback(item, index, arr);
}
if (item.children) {
return loopTree(item.children, key, callback);
}
});
};
const data = [...treeData];

let dragObj;
loopTree(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});

if (!info.dropToGap) {
loopTree(data, dropKey, (item) => {
item.children = item.children || [];
item.children.push(dragObj);
});
} else if (
(info.node.props.children || []).length > 0 &&
info.node.props.expanded &&
dropPosition === 1
) {
loopTree(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else {
let ar;
let i;
loopTree(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
console.log('data', data);
setTreeData(data);
};

const renderTreeNodes = (data) =>
data?.map((item) => {
return (
<TreeNode
data-id={generateTreeId(item.id)}
data={item}
title={item.title}
key={item.key}
icon={<Icon type={item.icon} />}
>
{item.children && renderTreeNodes(item.children)}
</TreeNode>
);
});
return (
<div className={classNames(prefixClaName('tree'), className)}>
<RcTree {...others} />
<div className={prefixClaName('tree', 'sidebar')}>
<Tree
{...others}
draggable
onDrop={onDrop}
switcherIcon={<Icon type="chevron-right" />}
onRightClick={({ event, node }: any) => {
setActiveData(node.data)
}}
onSelect={(selectedKeys, e) => { console.log('select', selectedKeys, e) }}
>
{renderTreeNodes(treeData)}
</Tree>
</div>
</div>
);
};
export const TreeNode = RcTree.TreeNode;
export default Tree;

export default memo(TreeView);

131 changes: 6 additions & 125 deletions src/extensions/explore/tree.tsx
Original file line number Diff line number Diff line change
@@ -1,128 +1,9 @@
import * as React from 'react';
import { memo, useEffect, useState } from 'react';
import Tree, { TreeNode } from 'mo/components/tree';
import { IMenuItem } from 'mo/components/menu';
import { Icon } from 'mo/components/icon';
import { prefixClaName } from 'mo/common/className';
import './style.scss';

export interface ITreeNodeItem {
title?: string;
key?: string;
type?: string;
contextMenu?: IMenuItem[];
children?: ITreeNodeItem[];
readonly id?: string;
icon?: string | React.ReactNode;
}
interface ITreeProps {
data: ITreeNodeItem[];
import * as React from 'react';
import { memo } from 'react';
import Tree from 'mo/components/tree';
// service
const TreeView: React.FunctionComponent<any> = (props: any) => {
return <Tree prefixCls="rc-tree" data={props.data} />
}
const TreeView: React.FunctionComponent<ITreeProps> = (props: ITreeProps) => {
const { data } = props;
const [treeData, setTreeData] = useState<ITreeNodeItem[]>(data);

/**
* Refer to antd for details
* TODO: move component
*/
const onDrop = (info) => {
console.log(info);
const dropKey = info.node.props.eventKey;
const dragKey = info.dragNode.props.eventKey;
const dropPos = info.node.props.pos.split('-');
const dropPosition =
info.dropPosition - Number(dropPos[dropPos.length - 1]);

const loopTree = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
return callback(item, index, arr);
}
if (item.children) {
return loopTree(item.children, key, callback);
}
});
};
const data = [...treeData];

// Find dragObject
let dragObj;
loopTree(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragObj = item;
});

if (!info.dropToGap) {
// Drop on the content
loopTree(data, dropKey, (item) => {
item.children = item.children || [];
item.children.push(dragObj);
});
} else if (
(info.node.props.children || []).length > 0 &&
info.node.props.expanded &&
dropPosition === 1
) {
loopTree(data, dropKey, (item) => {
item.children = item.children || [];
item.children.unshift(dragObj);
});
} else {
let ar;
let i;
loopTree(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
}
console.log('data', data);
setTreeData(data);
};

useEffect(() => {
return () => {
console.log('clean effect');
};
}, data);

const renderTreeNodes = (data) =>
data?.map((item) => {
return (
<TreeNode
data={item}
title={item.title}
key={item.key}
icon={<Icon type={item.icon} />}
>
{item.children && renderTreeNodes(item.children)}
</TreeNode>
);
});
return (
/**
* TODO: contextMenu、line
*/
<div className={prefixClaName('tree', 'sidebar')}>
<Tree
prefixCls="rc-tree"
draggable
onDrop={onDrop}
switcherIcon={<Icon type="chevron-right" />}
onRightClick={({ event, node }) => {
console.log('onRightClick', event, node);
}}
// onSelect={onClickItem}
>
{renderTreeNodes(treeData)}
</Tree>
</div>
);
};

export default memo(TreeView);
Loading

0 comments on commit d3f334a

Please sign in to comment.