|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- import { useCallback, useRef, useState } from 'react';
- import { NodeMouseHandler, useReactFlow } from 'reactflow';
-
- import styles from './index.less';
-
- export interface INodeContextMenu {
- id: string;
- top: number;
- left: number;
- right?: number;
- bottom?: number;
- [key: string]: unknown;
- }
-
- export function NodeContextMenu({
- id,
- top,
- left,
- right,
- bottom,
- ...props
- }: INodeContextMenu) {
- const { getNode, setNodes, addNodes, setEdges } = useReactFlow();
-
- const duplicateNode = useCallback(() => {
- const node = getNode(id);
- const position = {
- x: node?.position?.x || 0 + 50,
- y: node?.position?.y || 0 + 50,
- };
-
- addNodes({
- ...(node || {}),
- data: node?.data,
- selected: false,
- dragging: false,
- id: `${node?.id}-copy`,
- position,
- });
- }, [id, getNode, addNodes]);
-
- const deleteNode = useCallback(() => {
- setNodes((nodes) => nodes.filter((node) => node.id !== id));
- setEdges((edges) => edges.filter((edge) => edge.source !== id));
- }, [id, setNodes, setEdges]);
-
- return (
- <div
- style={{ top, left, right, bottom }}
- className={styles.contextMenu}
- {...props}
- >
- <p style={{ margin: '0.5em' }}>
- <small>node: {id}</small>
- </p>
- <button onClick={duplicateNode} type={'button'}>
- duplicate
- </button>
- <button onClick={deleteNode} type={'button'}>
- delete
- </button>
- </div>
- );
- }
-
- export const useHandleNodeContextMenu = (sideWidth: number) => {
- const [menu, setMenu] = useState<INodeContextMenu>({} as INodeContextMenu);
- const ref = useRef<any>(null);
-
- const onNodeContextMenu: NodeMouseHandler = useCallback(
- (event, node) => {
- // Prevent native context menu from showing
- event.preventDefault();
-
- // Calculate position of the context menu. We want to make sure it
- // doesn't get positioned off-screen.
- const pane = ref.current?.getBoundingClientRect();
- // setMenu({
- // id: node.id,
- // top: event.clientY < pane.height - 200 ? event.clientY : 0,
- // left: event.clientX < pane.width - 200 ? event.clientX : 0,
- // right: event.clientX >= pane.width - 200 ? pane.width - event.clientX : 0,
- // bottom:
- // event.clientY >= pane.height - 200 ? pane.height - event.clientY : 0,
- // });
-
- setMenu({
- id: node.id,
- top: event.clientY - 144,
- left: event.clientX - sideWidth,
- // top: event.clientY < pane.height - 200 ? event.clientY - 72 : 0,
- // left: event.clientX < pane.width - 200 ? event.clientX : 0,
- });
- },
- [sideWidth],
- );
-
- // Close the context menu if it's open whenever the window is clicked.
- const onPaneClick = useCallback(
- () => setMenu({} as INodeContextMenu),
- [setMenu],
- );
-
- return { onNodeContextMenu, menu, onPaneClick, ref };
- };
|