feat(nodes): add enter, move, leave and context handler #301
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useState, memo, ComponentType, CSSProperties } from 'react';
|
||||
import React, { useEffect, useRef, useState, memo, ComponentType, CSSProperties, useMemo, MouseEvent } from 'react';
|
||||
import { DraggableCore } from 'react-draggable';
|
||||
import cx from 'classnames';
|
||||
import { ResizeObserver } from 'resize-observer';
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
NodePosUpdate,
|
||||
} from '../../types';
|
||||
|
||||
import { noop } from '../../utils';
|
||||
|
||||
const getMouseEvent = (evt: MouseEvent | TouchEvent) =>
|
||||
typeof TouchEvent !== 'undefined' && evt instanceof TouchEvent ? evt.touches[0] : (evt as MouseEvent);
|
||||
|
||||
@@ -154,6 +156,10 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
yPos,
|
||||
selected,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
onMouseMove,
|
||||
onMouseLeave,
|
||||
onContextMenu,
|
||||
onNodeDragStart,
|
||||
onNodeDragStop,
|
||||
style,
|
||||
@@ -172,6 +178,38 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
const [isDragging, setDragging] = useState(false);
|
||||
const position = { x: xPos, y: yPos };
|
||||
const nodeClasses = cx('react-flow__node', `react-flow__node-${type}`, className, { selected });
|
||||
const node = { id, type, position, data };
|
||||
const onMouseEnterHandler = useMemo(() => {
|
||||
if (!onMouseEnter || isDragging) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
return (evt: MouseEvent) => onMouseEnter(evt, node);
|
||||
}, [onMouseEnter, isDragging]);
|
||||
|
||||
const onMouseMoveHandler = useMemo(() => {
|
||||
if (!onMouseMove || isDragging) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
return (evt: MouseEvent) => onMouseMove(evt, node);
|
||||
}, [onMouseMove, isDragging]);
|
||||
|
||||
const onMouseLeaveHandler = useMemo(() => {
|
||||
if (!onMouseLeave || isDragging) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
return (evt: MouseEvent) => onMouseLeave(evt, node);
|
||||
}, [onMouseLeave, isDragging]);
|
||||
|
||||
const onContextMenuHandler = useMemo(() => {
|
||||
if (!onContextMenu) {
|
||||
return noop;
|
||||
}
|
||||
|
||||
return (evt: MouseEvent) => onContextMenu(evt, node);
|
||||
}, [onContextMenu]);
|
||||
|
||||
const nodeStyle: CSSProperties = {
|
||||
zIndex: selected ? 10 : 3,
|
||||
@@ -237,7 +275,15 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
disabled={!isInteractive}
|
||||
cancel=".nodrag"
|
||||
>
|
||||
<div className={nodeClasses} ref={nodeElement} style={nodeStyle}>
|
||||
<div
|
||||
className={nodeClasses}
|
||||
ref={nodeElement}
|
||||
style={nodeStyle}
|
||||
onMouseEnter={onMouseEnterHandler}
|
||||
onMouseMove={onMouseMoveHandler}
|
||||
onMouseLeave={onMouseLeaveHandler}
|
||||
onContextMenu={onContextMenuHandler}
|
||||
>
|
||||
<Provider value={id}>
|
||||
<NodeComponent
|
||||
id={id}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, memo, CSSProperties } from 'react';
|
||||
import React, { useEffect, useRef, memo, CSSProperties, MouseEvent } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { ResizeObserver } from 'resize-observer';
|
||||
|
||||
@@ -28,6 +28,10 @@ export interface GraphViewProps {
|
||||
elements: Elements;
|
||||
onElementClick?: (element: Node | Edge) => void;
|
||||
onElementsRemove?: (elements: Elements) => void;
|
||||
onNodeMouseEnter?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseMove?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseLeave?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeContextMenu?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (node: Node) => void;
|
||||
onNodeDragStop?: (node: Node) => void;
|
||||
onConnect?: (connection: Connection | Edge) => void;
|
||||
@@ -56,6 +60,10 @@ const GraphView = memo(
|
||||
onMove,
|
||||
onLoad,
|
||||
onElementClick,
|
||||
onNodeMouseEnter,
|
||||
onNodeMouseMove,
|
||||
onNodeMouseLeave,
|
||||
onNodeContextMenu,
|
||||
onNodeDragStart,
|
||||
onNodeDragStop,
|
||||
connectionLineType,
|
||||
@@ -176,6 +184,10 @@ const GraphView = memo(
|
||||
<NodeRenderer
|
||||
nodeTypes={nodeTypes}
|
||||
onElementClick={onElementClick}
|
||||
onNodeMouseEnter={onNodeMouseEnter}
|
||||
onNodeMouseMove={onNodeMouseMove}
|
||||
onNodeMouseLeave={onNodeMouseLeave}
|
||||
onNodeContextMenu={onNodeContextMenu}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
onlyRenderVisibleNodes={onlyRenderVisibleNodes}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { memo, ComponentType } from 'react';
|
||||
import React, { memo, ComponentType, MouseEvent } from 'react';
|
||||
|
||||
import { useStoreState } from '../../store/hooks';
|
||||
import { getNodesInside } from '../../utils/graph';
|
||||
@@ -8,6 +8,10 @@ interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
selectNodesOnDrag: boolean;
|
||||
onElementClick?: (element: Node | Edge) => void;
|
||||
onNodeMouseEnter?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseMove?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseLeave?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeContextMenu?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (node: Node) => void;
|
||||
onNodeDragStop?: (node: Node) => void;
|
||||
onlyRenderVisibleNodes?: boolean;
|
||||
@@ -37,6 +41,10 @@ function renderNode(
|
||||
xPos={node.__rf.position.x}
|
||||
yPos={node.__rf.position.y}
|
||||
onClick={props.onElementClick}
|
||||
onMouseEnter={props.onNodeMouseEnter}
|
||||
onMouseMove={props.onNodeMouseMove}
|
||||
onMouseLeave={props.onNodeMouseLeave}
|
||||
onContextMenu={props.onNodeContextMenu}
|
||||
onNodeDragStart={props.onNodeDragStart}
|
||||
onNodeDragStop={props.onNodeDragStop}
|
||||
transform={transform}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, CSSProperties, HTMLAttributes } from 'react';
|
||||
import React, { useMemo, CSSProperties, HTMLAttributes, MouseEvent } from 'react';
|
||||
import cx from 'classnames';
|
||||
|
||||
const nodeEnv: string = process.env.NODE_ENV as string;
|
||||
@@ -37,6 +37,10 @@ export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'on
|
||||
elements: Elements;
|
||||
onElementClick?: (element: Node | Edge) => void;
|
||||
onElementsRemove?: (elements: Elements) => void;
|
||||
onNodeMouseEnter?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseMove?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeMouseLeave?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeContextMenu?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (node: Node) => void;
|
||||
onNodeDragStop?: (node: Node) => void;
|
||||
onConnect?: (connection: Edge | Connection) => void;
|
||||
@@ -71,6 +75,10 @@ const ReactFlow = ({
|
||||
onMove,
|
||||
onElementsRemove,
|
||||
onConnect,
|
||||
onNodeMouseEnter,
|
||||
onNodeMouseMove,
|
||||
onNodeMouseLeave,
|
||||
onNodeContextMenu,
|
||||
onNodeDragStart,
|
||||
onNodeDragStop,
|
||||
onSelectionChange,
|
||||
@@ -97,6 +105,10 @@ const ReactFlow = ({
|
||||
onLoad={onLoad}
|
||||
onMove={onMove}
|
||||
onElementClick={onElementClick}
|
||||
onNodeMouseEnter={onNodeMouseEnter}
|
||||
onNodeMouseMove={onNodeMouseMove}
|
||||
onNodeMouseLeave={onNodeMouseLeave}
|
||||
onNodeContextMenu={onNodeContextMenu}
|
||||
onNodeDragStart={onNodeDragStart}
|
||||
onNodeDragStop={onNodeDragStop}
|
||||
nodeTypes={nodeTypesParsed}
|
||||
|
||||
+9
-1
@@ -1,4 +1,4 @@
|
||||
import { CSSProperties } from 'react';
|
||||
import { CSSProperties, MouseEvent } from 'react';
|
||||
|
||||
export type ElementId = string;
|
||||
|
||||
@@ -109,6 +109,10 @@ export interface NodeComponentProps {
|
||||
targetPosition?: Position;
|
||||
sourcePosition?: Position;
|
||||
onClick?: (node: Node) => void;
|
||||
onMouseEnter?: (node: Node) => void;
|
||||
onMouseMove?: (node: Node) => void;
|
||||
onMouseLeave?: (node: Node) => void;
|
||||
onContextMenu?: (node: Node) => void;
|
||||
onNodeDragStart?: (node: Node) => void;
|
||||
onNodeDragStop?: (node: Node) => void;
|
||||
style?: CSSProperties;
|
||||
@@ -125,6 +129,10 @@ export interface WrapNodeProps {
|
||||
isInteractive: boolean;
|
||||
selectNodesOnDrag: boolean;
|
||||
onClick?: (node: Node) => void;
|
||||
onMouseEnter?: (evt: MouseEvent, node: Node) => void;
|
||||
onMouseMove?: (evt: MouseEvent, node: Node) => void;
|
||||
onMouseLeave?: (evt: MouseEvent, node: Node) => void;
|
||||
onContextMenu?: (evt: MouseEvent, node: Node) => void;
|
||||
onNodeDragStart?: (node: Node) => void;
|
||||
onNodeDragStop?: (node: Node) => void;
|
||||
style?: CSSProperties;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { DraggableEvent } from 'react-draggable';
|
||||
import { MouseEvent as ReactMouseEvent } from 'react';
|
||||
|
||||
export const noop = () => {};
|
||||
|
||||
export const isInputDOMNode = (e: ReactMouseEvent | DraggableEvent | KeyboardEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
return e && target && ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON'].includes(target.nodeName);
|
||||
|
||||
Reference in New Issue
Block a user