refactor context menu to separate component
This commit is contained in:
@@ -1,70 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { renderToStaticMarkup } from "react-dom/server";
|
|
||||||
|
|
||||||
export class NodeContextMenu {
|
|
||||||
contextMenu: ContextMenuInput | null;
|
|
||||||
setContextMenu: React.Dispatch<React.SetStateAction<ContextMenuInput | null>>;
|
|
||||||
|
|
||||||
constructor(containerRef: React.RefObject<null>) {
|
|
||||||
[this.contextMenu, this.setContextMenu] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if(!this.contextMenu){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const container = containerRef.current;
|
|
||||||
if (container) {
|
|
||||||
const menu = renderToStaticMarkup(this.render());
|
|
||||||
renderTo
|
|
||||||
(container as HTMLElement).append
|
|
||||||
}
|
|
||||||
}, [this.contextMenu]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const close = () => this.setContextMenu(null);
|
|
||||||
document.addEventListener('click', close);
|
|
||||||
return () => document.removeEventListener('click', close);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.contextMenu)
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="absolute bg-white border rounded shadow-lg z-50 p-2 text-sm"
|
|
||||||
style={{ left: this.contextMenu.x, top: this.contextMenu.y }}
|
|
||||||
onClick={e => e.stopPropagation()}
|
|
||||||
>
|
|
||||||
<div className="font-bold mb-1">Node: {this.contextMenu.nodeId}</div>
|
|
||||||
<button
|
|
||||||
className="block w-full text-left hover:bg-gray-100 px-2 py-1"
|
|
||||||
onClick={() => {
|
|
||||||
this.setContextMenu(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Edit subgraph
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="block w-full text-left hover:bg-gray-100 px-2 py-1"
|
|
||||||
onClick={() => {
|
|
||||||
this.setContextMenu(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Delete node
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ContextMenuInput {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
nodeId: string;
|
|
||||||
|
|
||||||
constructor(x: number, y: number, nodeId: string) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.nodeId = nodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
3
src/TODO
Normal file
3
src/TODO
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
- add not connected node in selected rank
|
||||||
|
- connect node
|
||||||
|
- remove connection
|
||||||
@@ -8,6 +8,7 @@ import { Modal } from "antd";
|
|||||||
import { Input } from "antd";
|
import { Input } from "antd";
|
||||||
import type { BreadcrumbItemType } from "antd/es/breadcrumb/Breadcrumb";
|
import type { BreadcrumbItemType } from "antd/es/breadcrumb/Breadcrumb";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
|
import NodeContextMenu from "./NodeContextMenu";
|
||||||
|
|
||||||
export class GraphModel {
|
export class GraphModel {
|
||||||
nodes: NodeModel[] = [];
|
nodes: NodeModel[] = [];
|
||||||
@@ -224,7 +225,10 @@ export default function Graph({ setGraphPath }) {
|
|||||||
<div ref={containerRef} className="w-full h-full bg-white rounded shadow" style={{ minHeight: '600px', overflow: 'auto' }}>
|
<div ref={containerRef} className="w-full h-full bg-white rounded shadow" style={{ minHeight: '600px', overflow: 'auto' }}>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Dropdown menu={{ items, onClick: onMenuClick }} trigger={['contextMenu']} open={contextMenuOpened} onOpenChange={contextMenuOpenChange} getPopupContainer={() => document.body}
|
<NodeContextMenu coords={coords} openContextMenu={openContextMenu} contextMenuOpened={contextMenuOpened}>
|
||||||
|
|
||||||
|
</NodeContextMenu>
|
||||||
|
{/* <Dropdown menu={{ items, onClick: onMenuClick }} trigger={['contextMenu']} open={contextMenuOpened} onOpenChange={contextMenuOpenChange} getPopupContainer={() => document.body}
|
||||||
// 👇 Key part: manually position the dropdown
|
// 👇 Key part: manually position the dropdown
|
||||||
overlayStyle={{
|
overlayStyle={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
@@ -232,7 +236,7 @@ export default function Graph({ setGraphPath }) {
|
|||||||
top: coords.y,
|
top: coords.y,
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
</Dropdown>
|
</Dropdown> */}
|
||||||
<Modal
|
<Modal
|
||||||
title="Rename"
|
title="Rename"
|
||||||
open={renameModalOpened}
|
open={renameModalOpened}
|
||||||
|
|||||||
66
src/components/NodeContextMenu.tsx
Normal file
66
src/components/NodeContextMenu.tsx
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { Dropdown, type MenuProps } from "antd";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const items: MenuProps['items'] = [
|
||||||
|
{
|
||||||
|
key: 'rename',
|
||||||
|
label: 'Rename',
|
||||||
|
extra: 'ctrl + n',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'subgraph',
|
||||||
|
label: 'Subgraph',
|
||||||
|
extra: 'ctrl + s',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'remove',
|
||||||
|
label: 'Remove',
|
||||||
|
extra: 'ctrl + r'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default function NodeContextMenu({
|
||||||
|
coords,
|
||||||
|
openContextMenu,
|
||||||
|
contextMenuOpened } :
|
||||||
|
{
|
||||||
|
coords: {x:number, y:number},
|
||||||
|
openContextMenu: React.Dispatch<React.SetStateAction<boolean>>,
|
||||||
|
contextMenuOpened: boolean
|
||||||
|
}) {
|
||||||
|
function contextMenuOpenChange(open: boolean) {
|
||||||
|
if (!open) {
|
||||||
|
openContextMenu(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMenuClick: MenuProps['onClick'] = ({ key }) => {
|
||||||
|
switch (key) {
|
||||||
|
case 'rename': {
|
||||||
|
//openRenameModal(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'remove': {
|
||||||
|
//removeNode(nodeId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'subgraph': {
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown menu={{ items, onClick: onMenuClick }} trigger={['contextMenu']} open={contextMenuOpened} onOpenChange={contextMenuOpenChange} getPopupContainer={() => document.body}
|
||||||
|
// 👇 Key part: manually position the dropdown
|
||||||
|
overlayStyle={{
|
||||||
|
position: "absolute",
|
||||||
|
left: coords.x,
|
||||||
|
top: coords.y,
|
||||||
|
}}>
|
||||||
|
|
||||||
|
</Dropdown>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user