refactor(connection): cleanup

This commit is contained in:
moklick
2023-01-24 14:17:55 +01:00
parent 0a2c96fe3e
commit f3806c6165
6 changed files with 61 additions and 34 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --port 3000 --open", "dev": "vite --port 3000 --open --host",
"serve": "vite serve --port 3000", "serve": "vite serve --port 3000",
"build": "vite build", "build": "vite build",
"test:dev": "cypress open", "test:dev": "cypress open",
+30 -24
View File
@@ -1,15 +1,18 @@
import type { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from 'react'; import type { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from 'react';
import { StoreApi } from 'zustand'; import { StoreApi } from 'zustand';
import { getHostForElement, calcAutoPan, getEventPosition, isMouseEvent } from '../../utils'; import { getHostForElement, calcAutoPan, getEventPosition } from '../../utils';
import type { OnConnect, HandleType, ReactFlowState } from '../../types'; import type { OnConnect, HandleType, ReactFlowState } from '../../types';
import { pointToRendererPoint, rendererPointToPoint } from '../../utils/graph'; import { pointToRendererPoint, rendererPointToPoint } from '../../utils/graph';
import { ConnectionHandle, getClosestHandle, getHandleLookup, isValidHandle, ValidConnectionFunc } from './utils'; import {
ConnectionHandle,
function resetRecentHandle(handleDomNode: Element): void { getClosestHandle,
handleDomNode?.classList.remove('react-flow__handle-valid'); getHandleLookup,
handleDomNode?.classList.remove('react-flow__handle-connecting'); getHandleType,
} isValidHandle,
resetRecentHandle,
ValidConnectionFunc,
} from './utils';
export function handlePointerDown({ export function handlePointerDown({
event, event,
@@ -20,7 +23,7 @@ export function handlePointerDown({
getState, getState,
setState, setState,
isValidConnection, isValidConnection,
elementEdgeUpdaterType, edgeUpdaterType,
onEdgeUpdateEnd, onEdgeUpdateEnd,
}: { }: {
event: ReactMouseEvent | ReactTouchEvent; event: ReactMouseEvent | ReactTouchEvent;
@@ -31,27 +34,34 @@ export function handlePointerDown({
getState: StoreApi<ReactFlowState>['getState']; getState: StoreApi<ReactFlowState>['getState'];
setState: StoreApi<ReactFlowState>['setState']; setState: StoreApi<ReactFlowState>['setState'];
isValidConnection: ValidConnectionFunc; isValidConnection: ValidConnectionFunc;
elementEdgeUpdaterType?: HandleType; edgeUpdaterType?: HandleType;
onEdgeUpdateEnd?: (evt: MouseEvent | TouchEvent) => void; onEdgeUpdateEnd?: (evt: MouseEvent | TouchEvent) => void;
}): void { }): void {
// 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);
const { connectionMode, domNode, autoPanOnConnect, connectionRadius, onConnectStart, onConnectEnd, panBy, getNodes } = const {
getState(); connectionMode,
domNode,
autoPanOnConnect,
connectionRadius,
onConnectStart,
onConnectEnd,
panBy,
getNodes,
cancelConnection,
} = getState();
let autoPanId = 0; let autoPanId = 0;
let prevClosestHandle: ConnectionHandle | null; let prevClosestHandle: ConnectionHandle | null;
const { clientX, clientY } = isMouseEvent(event) ? event : event.touches[0]!; const { x, y } = getEventPosition(event);
const clickedElement = doc?.elementFromPoint(clientX, clientY); const clickedHandle = doc?.elementFromPoint(x, y);
const elementIsTarget = clickedElement?.classList.contains('target'); const handleType = getHandleType(edgeUpdaterType, clickedHandle);
const elementIsSource = clickedElement?.classList.contains('source'); const containerBounds = domNode?.getBoundingClientRect();
if (!domNode || (!elementIsTarget && !elementIsSource && !elementEdgeUpdaterType)) { if (!containerBounds || !handleType) {
return; return;
} }
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementIsTarget ? 'target' : 'source';
const containerBounds = domNode.getBoundingClientRect();
let prevActiveHandle: Element; let prevActiveHandle: Element;
let connectionPosition = getEventPosition(event, containerBounds); let connectionPosition = getEventPosition(event, containerBounds);
let autoPanStarted = false; let autoPanStarted = false;
@@ -154,17 +164,13 @@ export function handlePointerDown({
onConnectEnd?.(event); onConnectEnd?.(event);
if (elementEdgeUpdaterType) { if (edgeUpdaterType) {
onEdgeUpdateEnd?.(event); onEdgeUpdateEnd?.(event);
} }
resetRecentHandle(prevActiveHandle); resetRecentHandle(prevActiveHandle);
setState({ cancelConnection();
connectionNodeId: null,
connectionHandleId: null,
connectionHandleType: null,
});
doc.removeEventListener('mousemove', onPointerMove as EventListener); doc.removeEventListener('mousemove', onPointerMove as EventListener);
doc.removeEventListener('mouseup', onPointerUp as EventListener); doc.removeEventListener('mouseup', onPointerUp as EventListener);
@@ -68,9 +68,9 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
}; };
const onPointerDown = (event: ReactMouseEvent<HTMLDivElement> | ReactTouchEvent<HTMLDivElement>) => { const onPointerDown = (event: ReactMouseEvent<HTMLDivElement> | ReactTouchEvent<HTMLDivElement>) => {
const isMouse = isMouseEvent(event); const isMouseTriggered = isMouseEvent(event);
if ((isMouse && event.button === 0) || 'touches' in event) { if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
handlePointerDown({ handlePointerDown({
event, event,
handleId, handleId,
@@ -83,7 +83,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
}); });
} }
if (isMouse) { if (isMouseTriggered) {
onMouseDown?.(event); onMouseDown?.(event);
} else { } else {
onTouchStart?.(event); onTouchStart?.(event);
@@ -132,3 +132,23 @@ export function getHandleLookup({ nodes, nodeId, handleId, handleType }: GetHand
return res; return res;
}, []); }, []);
} }
export function getHandleType(
edgeUpdaterType: HandleType | undefined,
handleDomNode: Element | null
): HandleType | null {
if (edgeUpdaterType) {
return edgeUpdaterType;
} else if (handleDomNode?.classList.contains('target')) {
return 'target';
} else if (handleDomNode?.classList.contains('source')) {
return 'source';
}
return null;
}
export function resetRecentHandle(handleDomNode: Element): void {
handleDomNode?.classList.remove('react-flow__handle-valid');
handleDomNode?.classList.remove('react-flow__handle-connecting');
}
+1
View File
@@ -273,6 +273,7 @@ const createRFStore = () =>
set({ set({
connectionNodeId: initialState.connectionNodeId, connectionNodeId: initialState.connectionNodeId,
connectionHandleId: initialState.connectionHandleId, connectionHandleId: initialState.connectionHandleId,
connectionHandleType: initialState.connectionHandleType,
}), }),
reset: () => set({ ...initialState }), reset: () => set({ ...initialState }),
})); }));
+6 -6
View File
@@ -122,14 +122,14 @@ export const isMouseEvent = (
export const getEventPosition = ( export const getEventPosition = (
event: MouseEvent | ReactMouseEvent | TouchEvent | ReactTouchEvent, event: MouseEvent | ReactMouseEvent | TouchEvent | ReactTouchEvent,
bounds: DOMRect bounds?: DOMRect
) => { ) => {
const isMouse = isMouseEvent(event); const isMouseTriggered = isMouseEvent(event);
const evtX = isMouse ? event.clientX : event.touches?.[0].clientX; const evtX = isMouseTriggered ? event.clientX : event.touches?.[0].clientX;
const evtY = isMouse ? event.clientY : event.touches?.[0].clientY; const evtY = isMouseTriggered ? event.clientY : event.touches?.[0].clientY;
return { return {
x: evtX - bounds.left, x: evtX - (bounds?.left ?? 0),
y: evtY - bounds.top, y: evtY - (bounds?.top ?? 0),
}; };
}; };