* fix(ts): use strict mode strictNullChecks etc

* chore: Use extended React.HTMLAttributes<> (#41)

* refactor(code-format): add prettier closes #42

* feat(renderer): add snap to grid option closes #20

* chore(dependabot): use develop as target branch
This commit is contained in:
Moritz
2019-10-21 20:58:28 +02:00
committed by GitHub
parent ce210eb5dc
commit a793f8c2ff
80 changed files with 2634 additions and 1247 deletions
+79 -42
View File
@@ -1,41 +1,54 @@
import React, { memo, MouseEvent as ReactMouseEvent } from 'react';
import cx from 'classnames';
import { HandleType, ElementId, Position, XYPosition, OnConnectFunc, Connection } from '../../types';
import {
HandleType,
ElementId,
Position,
XYPosition,
OnConnectFunc,
Connection,
} from '../../types';
type ValidConnectionFunc = (connection: Connection) => boolean;
type SetSourceIdFunc = (nodeId: ElementId | null) => void;
interface BaseHandleProps {
type: HandleType;
nodeId: ElementId;
onConnect: OnConnectFunc;
position: Position;
setSourceId: (nodeId: ElementId) => void;
setSourceId: SetSourceIdFunc;
setPosition: (pos: XYPosition) => void;
isValidConnection: ValidConnectionFunc;
id?: ElementId | boolean;
id?: ElementId | boolean;
className?: string;
};
}
type Result = {
elementBelow: Element;
elementBelow: Element | null;
isValid: boolean;
connection: Connection;
isHoveringHandle: boolean;
};
function onMouseDown(
evt: ReactMouseEvent, nodeId: ElementId, setSourceId: (nodeId: ElementId) => void, setPosition: (pos: XYPosition) => any,
onConnect: OnConnectFunc, isTarget: boolean, isValidConnection: ValidConnectionFunc
evt: ReactMouseEvent,
nodeId: ElementId,
setSourceId: SetSourceIdFunc,
setPosition: (pos: XYPosition) => any,
onConnect: OnConnectFunc,
isTarget: boolean,
isValidConnection: ValidConnectionFunc
): void {
const reactFlowNode = document.querySelector('.react-flow');
if (!reactFlowNode) {
return null;
return;
}
const containerBounds = reactFlowNode.getBoundingClientRect();
let recentHoveredHandle: Element = null;
let recentHoveredHandle: Element;
setPosition({
x: evt.clientX - containerBounds.left,
@@ -43,9 +56,9 @@ function onMouseDown(
});
setSourceId(nodeId);
function resetRecentHandle() {
function resetRecentHandle(): void {
if (!recentHoveredHandle) {
return false;
return;
}
recentHoveredHandle.classList.remove('valid');
@@ -55,14 +68,19 @@ function onMouseDown(
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
function checkElementBelowIsValid(evt: MouseEvent) {
const elementBelow = document.elementFromPoint(evt.clientX, evt.clientY);
const result: Result = {
elementBelow,
isValid: false,
connection: { source: null, target: null },
isHoveringHandle: false
isHoveringHandle: false,
};
if (elementBelow && (elementBelow.classList.contains('target') || elementBelow.classList.contains('source'))) {
if (
elementBelow &&
(elementBelow.classList.contains('target') ||
elementBelow.classList.contains('source'))
) {
let connection: Connection = { source: null, target: null };
if (isTarget) {
@@ -89,7 +107,12 @@ function onMouseDown(
y: evt.clientY - containerBounds.top,
});
const { connection, elementBelow, isValid, isHoveringHandle } = checkElementBelowIsValid(evt);
const {
connection,
elementBelow,
isValid,
isHoveringHandle,
} = checkElementBelowIsValid(evt);
if (!isHoveringHandle) {
return resetRecentHandle();
@@ -97,7 +120,7 @@ function onMouseDown(
const isOwnHandle = connection.source === connection.target;
if (!isOwnHandle) {
if (!isOwnHandle && elementBelow) {
recentHoveredHandle = elementBelow;
elementBelow.classList.add('connecting');
elementBelow.classList.toggle('valid', isValid);
@@ -105,7 +128,7 @@ function onMouseDown(
}
function onMouseUp(evt: MouseEvent) {
const { connection, isValid } = checkElementBelowIsValid(evt);
const { connection, isValid } = checkElementBelowIsValid(evt);
if (isValid) {
onConnect(connection);
@@ -119,37 +142,51 @@ function onMouseDown(
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp)
document.addEventListener('mouseup', onMouseUp);
}
const BaseHandle = memo(({
type, nodeId, onConnect, position,
setSourceId, setPosition, className,
id = false, isValidConnection, ...rest
}: BaseHandleProps) => {
const isTarget = type === 'target';
const handleClasses = cx(
'react-flow__handle',
className,
const BaseHandle = memo(
({
type,
nodeId,
onConnect,
position,
{ source: !isTarget, target: isTarget }
);
setSourceId,
setPosition,
className,
id = false,
isValidConnection,
...rest
}: BaseHandleProps) => {
const isTarget = type === 'target';
const handleClasses = cx('react-flow__handle', className, position, {
source: !isTarget,
target: isTarget,
});
const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId;
const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId;
return (
<div
data-nodeid={nodeIdWithHandleId}
data-handlepos={position}
className={handleClasses}
onMouseDown={evt => onMouseDown(evt,
nodeIdWithHandleId, setSourceId, setPosition,
onConnect, isTarget, isValidConnection
)}
{...rest}
/>
);
});
return (
<div
data-nodeid={nodeIdWithHandleId}
data-handlepos={position}
className={handleClasses}
onMouseDown={evt =>
onMouseDown(
evt,
nodeIdWithHandleId,
setSourceId,
setPosition,
onConnect,
isTarget,
isValidConnection
)
}
{...rest}
/>
);
}
);
BaseHandle.displayName = 'BaseHandle';
+45 -34
View File
@@ -2,45 +2,56 @@ import React, { memo, useContext } from 'react';
import { useStoreActions, useStoreState } from '../../store/hooks';
import BaseHandle from './BaseHandle';
import NodeIdContext from '../../contexts/NodeIdContext'
import NodeIdContext from '../../contexts/NodeIdContext';
import { HandleType, ElementId, Position, OnConnectParams, OnConnectFunc } from '../../types';
import {
HandleType,
ElementId,
Position,
Connection,
OnConnectFunc,
} from '../../types';
interface HandleProps {
type: HandleType,
position: Position,
onConnect?: OnConnectFunc,
isValidConnection?: () => boolean
};
type: HandleType;
position: Position;
onConnect?: OnConnectFunc;
isValidConnection?: () => boolean;
}
const Handle = memo(({
onConnect = _ => {}, type = 'source', position = 'top', isValidConnection = () => true,
...rest
}: HandleProps) => {
const nodeId = useContext(NodeIdContext) as ElementId;
const { setPosition, setSourceId } = useStoreActions(a => ({
setPosition: a.setConnectionPosition,
setSourceId: a.setConnectionSourceId
}));
const onConnectAction = useStoreState(s => s.onConnect);
const onConnectExtended = (params: OnConnectParams) => {
onConnectAction(params);
onConnect(params);
};
const Handle = memo(
({
onConnect = _ => {},
type = 'source',
position = 'top',
isValidConnection = () => true,
...rest
}: HandleProps) => {
const nodeId = useContext(NodeIdContext) as ElementId;
const { setPosition, setSourceId } = useStoreActions(a => ({
setPosition: a.setConnectionPosition,
setSourceId: a.setConnectionSourceId,
}));
const onConnectAction = useStoreState(s => s.onConnect);
const onConnectExtended = (params: Connection) => {
onConnectAction(params);
onConnect(params);
};
return (
<BaseHandle
nodeId={nodeId}
setPosition={setPosition}
setSourceId={setSourceId}
onConnect={onConnectExtended}
type={type}
position={position}
isValidConnection={isValidConnection}
{...rest}
/>
);
});
return (
<BaseHandle
nodeId={nodeId}
setPosition={setPosition}
setSourceId={setSourceId}
onConnect={onConnectExtended}
type={type}
position={position}
isValidConnection={isValidConnection}
{...rest}
/>
);
}
);
Handle.displayName = 'Handle';