refactor(onConnect): use onConnect handlers from store #2230

This commit is contained in:
moklick
2022-07-18 12:52:17 +02:00
parent 8a4f695ad7
commit 3c8720a5cf
4 changed files with 73 additions and 88 deletions
+26 -11
View File
@@ -1,4 +1,4 @@
import { MouseEvent as ReactMouseEvent, FC } from 'react'; import { FC, useCallback, useState } from 'react';
import ReactFlow, { import ReactFlow, {
addEdge, addEdge,
Handle, Handle,
@@ -6,11 +6,11 @@ import ReactFlow, {
Position, Position,
Node, Node,
Edge, Edge,
OnConnectStartParams,
NodeProps, NodeProps,
NodeTypes, NodeTypes,
useNodesState, useNodesState,
useEdgesState, useEdgesState,
OnConnectStartParams,
} from 'react-flow-renderer'; } from 'react-flow-renderer';
import './validation.css'; import './validation.css';
@@ -23,10 +23,6 @@ const initialNodes: Node[] = [
]; ];
const isValidConnection = (connection: Connection) => connection.target === 'B'; const isValidConnection = (connection: Connection) => connection.target === 'B';
const onConnectStart = (_: ReactMouseEvent, { nodeId, handleType }: OnConnectStartParams) =>
console.log('on connect start', { nodeId, handleType });
const onConnectStop = (event: MouseEvent) => console.log('on connect stop', event);
const onConnectEnd = (event: MouseEvent) => console.log('on connect end', event);
const CustomInput: FC<NodeProps> = () => ( const CustomInput: FC<NodeProps> = () => (
<> <>
@@ -49,13 +45,33 @@ const nodeTypes: NodeTypes = {
}; };
const ValidationFlow = () => { const ValidationFlow = () => {
const [value, setValue] = useState(0);
const [nodes, , onNodesChange] = useNodesState(initialNodes); const [nodes, , onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState([]); const [edges, setEdges, onEdgesChange] = useEdgesState([]);
const onConnect = (params: Connection | Edge) => { const onConnectStart = useCallback(
console.log('on connect', params); (event: React.MouseEvent, params: OnConnectStartParams) => {
setEdges((eds) => addEdge(params, eds)); console.log('on connect start', params, event, value);
}; setValue(1);
},
[value]
);
const onConnect = useCallback(
(params: Connection | Edge) => {
console.log('on connect', params);
setEdges((eds) => addEdge(params, eds));
},
[setEdges]
);
const onConnectEnd = useCallback(
(event: MouseEvent) => {
console.log('on connect end', event, value);
setValue(0);
},
[value]
);
return ( return (
<ReactFlow <ReactFlow
@@ -68,7 +84,6 @@ const ValidationFlow = () => {
className="validationflow" className="validationflow"
nodeTypes={nodeTypes} nodeTypes={nodeTypes}
onConnectStart={onConnectStart} onConnectStart={onConnectStart}
onConnectStop={onConnectStop}
onConnectEnd={onConnectEnd} onConnectEnd={onConnectEnd}
fitView fitView
/> />
+12 -19
View File
@@ -1,19 +1,13 @@
import React, { memo, ComponentType, useState, useMemo } from 'react'; import React, { memo, ComponentType, useState, useMemo } from 'react';
import cc from 'classcat'; import cc from 'classcat';
import shallow from 'zustand/shallow';
import { useStore, useStoreApi } from '../../store'; import { useStoreApi } from '../../store';
import { EdgeProps, WrapEdgeProps, ReactFlowState, Connection } from '../../types'; import { EdgeProps, WrapEdgeProps, Connection } from '../../types';
import { handleMouseDown } from '../../components/Handle/handler'; import { handleMouseDown } from '../../components/Handle/handler';
import { EdgeAnchor } from './EdgeAnchor'; import { EdgeAnchor } from './EdgeAnchor';
import { getMarkerId } from '../../utils/graph'; import { getMarkerId } from '../../utils/graph';
import { getMouseHandler } from './utils'; import { getMouseHandler } from './utils';
const selector = (s: ReactFlowState) => ({
addSelectedEdges: s.addSelectedEdges,
connectionMode: s.connectionMode,
});
export default (EdgeComponent: ComponentType<EdgeProps>) => { export default (EdgeComponent: ComponentType<EdgeProps>) => {
const EdgeWrapper = ({ const EdgeWrapper = ({
id, id,
@@ -56,11 +50,11 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
rfId, rfId,
}: WrapEdgeProps): JSX.Element | null => { }: WrapEdgeProps): JSX.Element | null => {
const [updating, setUpdating] = useState<boolean>(false); const [updating, setUpdating] = useState<boolean>(false);
const { addSelectedEdges, connectionMode } = useStore(selector, shallow);
const store = useStoreApi(); const store = useStoreApi();
const onEdgeClick = (event: React.MouseEvent<SVGGElement, MouseEvent>): void => { const onEdgeClick = (event: React.MouseEvent<SVGGElement, MouseEvent>): void => {
const edge = store.getState().edges.find((e) => e.id === id)!; const { edges, addSelectedEdges } = store.getState();
const edge = edges.find((e) => e.id === id)!;
if (elementsSelectable) { if (elementsSelectable) {
store.setState({ nodesSelectionActive: false }); store.setState({ nodesSelectionActive: false });
@@ -86,7 +80,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
onEdgeUpdateStart?.(event, edge, handleType); onEdgeUpdateStart?.(event, edge, handleType);
const _onEdgeUpdate = onEdgeUpdateEnd const _onEdgeUpdateEnd = onEdgeUpdateEnd
? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType) ? (evt: MouseEvent): void => onEdgeUpdateEnd(evt, edge, handleType)
: undefined; : undefined;
@@ -99,19 +93,18 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
} }
}; };
handleMouseDown( handleMouseDown({
event, event,
handleId, handleId,
nodeId, nodeId,
store.setState, onConnect: onConnectEdge,
onConnectEdge,
isTarget, isTarget,
getState: store.getState,
setState: store.setState,
isValidConnection, isValidConnection,
connectionMode, elementEdgeUpdaterType: handleType,
handleType, onEdgeUpdateEnd: _onEdgeUpdateEnd,
_onEdgeUpdate, });
store.getState
);
}; };
const onEdgeUpdaterSourceMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void => const onEdgeUpdaterSourceMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
+27 -26
View File
@@ -1,17 +1,8 @@
import { MouseEvent as ReactMouseEvent } from 'react'; import { MouseEvent as ReactMouseEvent } from 'react';
import { SetState } from 'zustand'; import { GetState, SetState } from 'zustand';
import { getHostForElement } from '../../utils'; import { getHostForElement } from '../../utils';
import { import { OnConnect, ConnectionMode, Connection, HandleType, ReactFlowState } from '../../types';
OnConnect,
OnConnectStart,
OnConnectStop,
OnConnectEnd,
ConnectionMode,
Connection,
HandleType,
ReactFlowState,
} from '../../types';
type ValidConnectionFunc = (connection: Connection) => boolean; type ValidConnectionFunc = (connection: Connection) => boolean;
@@ -83,21 +74,29 @@ function resetRecentHandle(hoveredHandle: Element): void {
hoveredHandle?.classList.remove('react-flow__handle-connecting'); hoveredHandle?.classList.remove('react-flow__handle-connecting');
} }
export function handleMouseDown( export function handleMouseDown({
event: ReactMouseEvent, event,
handleId: string | null, handleId,
nodeId: string, nodeId,
setState: SetState<ReactFlowState>, onConnect,
onConnect: OnConnect, isTarget,
isTarget: boolean, getState,
isValidConnection: ValidConnectionFunc, setState,
connectionMode: ConnectionMode, isValidConnection,
elementEdgeUpdaterType?: HandleType, elementEdgeUpdaterType,
onEdgeUpdateEnd?: (evt: MouseEvent) => void, onEdgeUpdateEnd,
onConnectStart?: OnConnectStart, }: {
onConnectStop?: OnConnectStop, event: ReactMouseEvent;
onConnectEnd?: OnConnectEnd handleId: string | null;
): void { nodeId: string;
onConnect: OnConnect;
isTarget: boolean;
getState: GetState<ReactFlowState>;
setState: SetState<ReactFlowState>;
isValidConnection: ValidConnectionFunc;
elementEdgeUpdaterType?: HandleType;
onEdgeUpdateEnd?: (evt: MouseEvent) => void;
}): void {
const reactFlowNode = (event.target as Element).closest('.react-flow'); const reactFlowNode = (event.target as Element).closest('.react-flow');
// when react-flow is used inside a shadow root we can't use document // when react-flow is used inside a shadow root we can't use document
const doc = getHostForElement(event.target as HTMLElement); const doc = getHostForElement(event.target as HTMLElement);
@@ -114,6 +113,7 @@ export function handleMouseDown(
return; return;
} }
const { onConnectStart, connectionMode } = getState();
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source'; const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source';
const containerBounds = reactFlowNode.getBoundingClientRect(); const containerBounds = reactFlowNode.getBoundingClientRect();
let recentHoveredHandle: Element; let recentHoveredHandle: Element;
@@ -160,6 +160,7 @@ export function handleMouseDown(
} }
function onMouseUp(event: MouseEvent) { function onMouseUp(event: MouseEvent) {
const { onConnectStop, onConnectEnd } = getState();
const { connection, isValid } = checkElementBelowIsValid( const { connection, isValid } = checkElementBelowIsValid(
event, event,
connectionMode, connectionMode,
+8 -32
View File
@@ -14,14 +14,6 @@ const alwaysValid = () => true;
export type HandleComponentProps = HandleProps & Omit<HTMLAttributes<HTMLDivElement>, 'id'>; export type HandleComponentProps = HandleProps & Omit<HTMLAttributes<HTMLDivElement>, 'id'>;
const selector = (s: ReactFlowState) => ({ const selector = (s: ReactFlowState) => ({
onConnectAction: s.onConnect,
onConnectStart: s.onConnectStart,
onConnectStop: s.onConnectStop,
onConnectEnd: s.onConnectEnd,
onClickConnectStart: s.onClickConnectStart,
onClickConnectStop: s.onClickConnectStop,
onClickConnectEnd: s.onClickConnectEnd,
connectionMode: s.connectionMode,
connectionStartHandle: s.connectionStartHandle, connectionStartHandle: s.connectionStartHandle,
connectOnClick: s.connectOnClick, connectOnClick: s.connectOnClick,
hasDefaultEdges: s.hasDefaultEdges, hasDefaultEdges: s.hasDefaultEdges,
@@ -45,25 +37,13 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
) => { ) => {
const store = useStoreApi(); const store = useStoreApi();
const nodeId = useContext(NodeIdContext) as string; const nodeId = useContext(NodeIdContext) as string;
const { const { connectionStartHandle, connectOnClick, hasDefaultEdges } = useStore(selector, shallow);
onConnectAction,
onConnectStart,
onConnectStop,
onConnectEnd,
onClickConnectStart,
onClickConnectStop,
onClickConnectEnd,
connectionMode,
connectionStartHandle,
connectOnClick,
hasDefaultEdges,
} = useStore(selector, shallow);
const handleId = id || null; const handleId = id || null;
const isTarget = type === 'target'; const isTarget = type === 'target';
const onConnectExtended = (params: Connection) => { const onConnectExtended = (params: Connection) => {
const { defaultEdgeOptions } = store.getState(); const { defaultEdgeOptions, onConnect: onConnectAction } = store.getState();
const edgeParams = { const edgeParams = {
...defaultEdgeOptions, ...defaultEdgeOptions,
@@ -80,26 +60,22 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
const onMouseDownHandler = (event: React.MouseEvent<HTMLDivElement>) => { const onMouseDownHandler = (event: React.MouseEvent<HTMLDivElement>) => {
if (event.button === 0) { if (event.button === 0) {
handleMouseDown( handleMouseDown({
event, event,
handleId, handleId,
nodeId, nodeId,
store.setState, onConnect: onConnectExtended,
onConnectExtended,
isTarget, isTarget,
getState: store.getState,
setState: store.setState,
isValidConnection, isValidConnection,
connectionMode, });
undefined,
undefined,
onConnectStart,
onConnectStop,
onConnectEnd
);
} }
onMouseDown?.(event); onMouseDown?.(event);
}; };
const onClick = (event: React.MouseEvent) => { const onClick = (event: React.MouseEvent) => {
const { onClickConnectStart, onClickConnectStop, onClickConnectEnd, connectionMode } = store.getState();
if (!connectionStartHandle) { if (!connectionStartHandle) {
onClickConnectStart?.(event, { nodeId, handleId, handleType: type }); onClickConnectStart?.(event, { nodeId, handleId, handleType: type });
store.setState({ connectionStartHandle: { nodeId, type, handleId } }); store.setState({ connectionStartHandle: { nodeId, type, handleId } });