refactor(callbacks): dont provide noops as defaults, but make cbs optional
This commit is contained in:
@@ -13,7 +13,7 @@ interface EdgeWrapperProps {
|
|||||||
labelStyle?: CSSProperties;
|
labelStyle?: CSSProperties;
|
||||||
labelShowBg?: boolean;
|
labelShowBg?: boolean;
|
||||||
labelBgStyle: CSSProperties;
|
labelBgStyle: CSSProperties;
|
||||||
onClick: (edge: Edge) => void;
|
onClick?: (edge: Edge) => void;
|
||||||
animated: boolean;
|
animated: boolean;
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
isInteractive: boolean;
|
isInteractive: boolean;
|
||||||
@@ -46,7 +46,10 @@ export default (EdgeComponent: ComponentType<EdgeCompProps>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch.setSelectedElements({ id, source, target });
|
store.dispatch.setSelectedElements({ id, source, target });
|
||||||
onClick({ id, source, target, type });
|
|
||||||
|
if (onClick) {
|
||||||
|
onClick({ id, source, target, type });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -10,16 +10,27 @@ import { Node, XYPosition, Transform, ElementId, NodeComponentProps, WrapNodePro
|
|||||||
const getMouseEvent = (evt: MouseEvent | TouchEvent) =>
|
const getMouseEvent = (evt: MouseEvent | TouchEvent) =>
|
||||||
typeof TouchEvent !== 'undefined' && evt instanceof TouchEvent ? evt.touches[0] : (evt as MouseEvent);
|
typeof TouchEvent !== 'undefined' && evt instanceof TouchEvent ? evt.touches[0] : (evt as MouseEvent);
|
||||||
|
|
||||||
const onStart = (
|
interface OnDragStartParams {
|
||||||
evt: MouseEvent | TouchEvent,
|
evt: MouseEvent | TouchEvent;
|
||||||
onDragStart: (node: Node) => void,
|
id: ElementId;
|
||||||
id: ElementId,
|
type: string;
|
||||||
type: string,
|
data: any;
|
||||||
data: any,
|
setOffset: (pos: XYPosition) => void;
|
||||||
setOffset: (pos: XYPosition) => void,
|
transform: Transform;
|
||||||
transform: Transform,
|
position: XYPosition;
|
||||||
position: XYPosition
|
onNodeDragStart?: (node: Node) => void;
|
||||||
): false | void => {
|
}
|
||||||
|
|
||||||
|
const onStart = ({
|
||||||
|
evt,
|
||||||
|
onNodeDragStart,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
setOffset,
|
||||||
|
transform,
|
||||||
|
position,
|
||||||
|
}: OnDragStartParams): false | void => {
|
||||||
const startEvt = getMouseEvent(evt);
|
const startEvt = getMouseEvent(evt);
|
||||||
|
|
||||||
const scaledClient: XYPosition = {
|
const scaledClient: XYPosition = {
|
||||||
@@ -33,16 +44,21 @@ const onStart = (
|
|||||||
|
|
||||||
store.dispatch.setSelectedElements({ id, type } as Node);
|
store.dispatch.setSelectedElements({ id, type } as Node);
|
||||||
setOffset({ x: offsetX, y: offsetY });
|
setOffset({ x: offsetX, y: offsetY });
|
||||||
onDragStart(node);
|
|
||||||
|
if (onNodeDragStart) {
|
||||||
|
onNodeDragStart(node);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDrag = (
|
interface OnDragParams {
|
||||||
evt: MouseEvent | TouchEvent,
|
evt: MouseEvent | TouchEvent;
|
||||||
setDragging: (isDragging: boolean) => void,
|
setDragging: (isDragging: boolean) => void;
|
||||||
id: ElementId,
|
id: ElementId;
|
||||||
offset: XYPosition,
|
offset: XYPosition;
|
||||||
transform: Transform
|
transform: Transform;
|
||||||
): void => {
|
}
|
||||||
|
|
||||||
|
const onDrag = ({ evt, setDragging, id, offset, transform }: OnDragParams): void => {
|
||||||
const dragEvt = getMouseEvent(evt);
|
const dragEvt = getMouseEvent(evt);
|
||||||
|
|
||||||
const scaledClient = {
|
const scaledClient = {
|
||||||
@@ -60,16 +76,27 @@ const onDrag = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onStop = (
|
interface OnDragStopParams {
|
||||||
onDragStop: (node: Node) => void,
|
isDragging: boolean;
|
||||||
onClick: (node: Node) => void,
|
setDragging: (isDragging: boolean) => void;
|
||||||
isDragging: boolean,
|
id: ElementId;
|
||||||
setDragging: (isDragging: boolean) => void,
|
type: string;
|
||||||
id: ElementId,
|
position: XYPosition;
|
||||||
type: string,
|
data: any;
|
||||||
position: XYPosition,
|
onNodeDragStop?: (node: Node) => void;
|
||||||
data: any
|
onClick?: (node: Node) => void;
|
||||||
): void => {
|
}
|
||||||
|
|
||||||
|
const onStop = ({
|
||||||
|
onNodeDragStop,
|
||||||
|
onClick,
|
||||||
|
isDragging,
|
||||||
|
setDragging,
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
position,
|
||||||
|
data,
|
||||||
|
}: OnDragStopParams): void => {
|
||||||
const node = {
|
const node = {
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
@@ -77,12 +104,15 @@ const onStop = (
|
|||||||
data,
|
data,
|
||||||
} as Node;
|
} as Node;
|
||||||
|
|
||||||
if (!isDragging) {
|
if (!isDragging && onClick) {
|
||||||
return onClick(node);
|
return onClick(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDragging(false);
|
setDragging(false);
|
||||||
onDragStop(node);
|
|
||||||
|
if (onNodeDragStop) {
|
||||||
|
onNodeDragStop(node);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||||
@@ -146,9 +176,11 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DraggableCore
|
<DraggableCore
|
||||||
onStart={(evt) => onStart(evt as MouseEvent, onNodeDragStart, id, type, data, setOffset, transform, position)}
|
onStart={(evt) =>
|
||||||
onDrag={(evt) => onDrag(evt as MouseEvent, setDragging, id, offset, transform)}
|
onStart({ evt: evt as MouseEvent, onNodeDragStart, id, type, data, setOffset, transform, position })
|
||||||
onStop={() => onStop(onNodeDragStop, onClick, isDragging, setDragging, id, type, position, data)}
|
}
|
||||||
|
onDrag={(evt) => onDrag({ evt: evt as MouseEvent, setDragging, id, offset, transform })}
|
||||||
|
onStop={() => onStop({ onNodeDragStop, onClick, isDragging, setDragging, id, type, position, data })}
|
||||||
scale={transform[2]}
|
scale={transform[2]}
|
||||||
disabled={!isInteractive}
|
disabled={!isInteractive}
|
||||||
cancel=".nodrag"
|
cancel=".nodrag"
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import { Elements, NodeTypesType, EdgeTypesType, OnLoadFunc, Node, Edge, Connect
|
|||||||
|
|
||||||
export interface GraphViewProps {
|
export interface GraphViewProps {
|
||||||
elements: Elements;
|
elements: Elements;
|
||||||
onElementClick: (element: Node | Edge) => void;
|
onElementClick?: (element: Node | Edge) => void;
|
||||||
onElementsRemove: (elements: Elements) => void;
|
onElementsRemove?: (elements: Elements) => void;
|
||||||
onNodeDragStart: (node: Node) => void;
|
onNodeDragStart?: (node: Node) => void;
|
||||||
onNodeDragStop: (node: Node) => void;
|
onNodeDragStop?: (node: Node) => void;
|
||||||
onConnect: (connection: Connection | Edge) => void;
|
onConnect?: (connection: Connection | Edge) => void;
|
||||||
onLoad: OnLoadFunc;
|
onLoad?: OnLoadFunc;
|
||||||
onMove: () => void;
|
onMove?: () => void;
|
||||||
selectionKeyCode: number;
|
selectionKeyCode: number;
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
edgeTypes: EdgeTypesType;
|
edgeTypes: EdgeTypesType;
|
||||||
@@ -92,18 +92,21 @@ const GraphView = memo(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateDimensions();
|
updateDimensions();
|
||||||
setOnConnect(onConnect);
|
|
||||||
window.onresize = updateDimensions;
|
window.onresize = updateDimensions;
|
||||||
|
|
||||||
|
if (onConnect) {
|
||||||
|
setOnConnect(onConnect);
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.onresize = null;
|
window.onresize = null;
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useD3Zoom(zoomPane, onMove, selectionKeyPressed);
|
useD3Zoom({ zoomPane, onMove, selectionKeyPressed });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.d3Initialised) {
|
if (state.d3Initialised && onLoad) {
|
||||||
onLoad({
|
onLoad({
|
||||||
fitView,
|
fitView,
|
||||||
zoomIn,
|
zoomIn,
|
||||||
@@ -111,7 +114,7 @@ const GraphView = memo(
|
|||||||
project,
|
project,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [state.d3Initialised]);
|
}, [state.d3Initialised, onLoad]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSnapGrid({ snapToGrid, snapGrid });
|
setSnapGrid({ snapToGrid, snapGrid });
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { Node, Transform, NodeTypesType, WrapNodeProps, Elements, Edge } from '.
|
|||||||
|
|
||||||
interface NodeRendererProps {
|
interface NodeRendererProps {
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
onElementClick: (element: Node | Edge) => void;
|
onElementClick?: (element: Node | Edge) => void;
|
||||||
onNodeDragStart: (node: Node) => void;
|
onNodeDragStart?: (node: Node) => void;
|
||||||
onNodeDragStop: (node: Node) => void;
|
onNodeDragStop?: (node: Node) => void;
|
||||||
onlyRenderVisibleNodes?: boolean;
|
onlyRenderVisibleNodes?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ function renderNode(
|
|||||||
const nodeType = node.type || 'default';
|
const nodeType = node.type || 'default';
|
||||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
||||||
if (!props.nodeTypes[nodeType]) {
|
if (!props.nodeTypes[nodeType]) {
|
||||||
console.warn(`No node type found for type "${nodeType}". Using fallback type "default".`);
|
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSelected = selectedElements ? selectedElements.some(({ id }) => id === node.id) : false;
|
const isSelected = selectedElements ? selectedElements.some(({ id }) => id === node.id) : false;
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ import '../../style.css';
|
|||||||
|
|
||||||
export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad'> {
|
export interface ReactFlowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onLoad'> {
|
||||||
elements: Elements;
|
elements: Elements;
|
||||||
onElementClick: (element: Node | Edge) => void;
|
onElementClick?: (element: Node | Edge) => void;
|
||||||
onElementsRemove: (elements: Elements) => void;
|
onElementsRemove?: (elements: Elements) => void;
|
||||||
onNodeDragStart: (node: Node) => void;
|
onNodeDragStart?: (node: Node) => void;
|
||||||
onNodeDragStop: (node: Node) => void;
|
onNodeDragStop?: (node: Node) => void;
|
||||||
onConnect: (connection: Edge | Connection) => void;
|
onConnect?: (connection: Edge | Connection) => void;
|
||||||
onLoad: OnLoadFunc;
|
onLoad?: OnLoadFunc;
|
||||||
onMove: () => void;
|
onMove?: () => void;
|
||||||
onSelectionChange: (elements: Elements | null) => void;
|
onSelectionChange?: (elements: Elements | null) => void;
|
||||||
nodeTypes: NodeTypesType;
|
nodeTypes: NodeTypesType;
|
||||||
edgeTypes: EdgeTypesType;
|
edgeTypes: EdgeTypesType;
|
||||||
connectionLineType: string;
|
connectionLineType: string;
|
||||||
@@ -106,13 +106,6 @@ const ReactFlow = ({
|
|||||||
ReactFlow.displayName = 'ReactFlow';
|
ReactFlow.displayName = 'ReactFlow';
|
||||||
|
|
||||||
ReactFlow.defaultProps = {
|
ReactFlow.defaultProps = {
|
||||||
onElementClick: () => {},
|
|
||||||
onElementsRemove: () => {},
|
|
||||||
onNodeDragStart: () => {},
|
|
||||||
onNodeDragStop: () => {},
|
|
||||||
onConnect: () => {},
|
|
||||||
onLoad: () => {},
|
|
||||||
onMove: () => {},
|
|
||||||
nodeTypes: {
|
nodeTypes: {
|
||||||
input: InputNode,
|
input: InputNode,
|
||||||
default: DefaultNode,
|
default: DefaultNode,
|
||||||
|
|||||||
+15
-7
@@ -4,20 +4,26 @@ import { select, event } from 'd3-selection';
|
|||||||
|
|
||||||
import { useStoreState, useStoreActions } from '../store/hooks';
|
import { useStoreState, useStoreActions } from '../store/hooks';
|
||||||
|
|
||||||
|
interface UseD3ZoomParams {
|
||||||
|
zoomPane: MutableRefObject<Element | null>;
|
||||||
|
selectionKeyPressed: boolean;
|
||||||
|
onMove?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
const d3ZoomInstance = d3Zoom
|
const d3ZoomInstance = d3Zoom
|
||||||
.zoom()
|
.zoom()
|
||||||
.scaleExtent([0.5, 2])
|
.scaleExtent([0.5, 2])
|
||||||
.filter(() => !event.button);
|
.filter(() => !event.button);
|
||||||
|
|
||||||
export default (zoomPane: MutableRefObject<Element | null>, onMove: () => void, shiftPressed: boolean): void => {
|
export default ({ zoomPane, onMove, selectionKeyPressed }: UseD3ZoomParams): void => {
|
||||||
const state = useStoreState(s => ({
|
const state = useStoreState((s) => ({
|
||||||
transform: s.transform,
|
transform: s.transform,
|
||||||
d3Selection: s.d3Selection,
|
d3Selection: s.d3Selection,
|
||||||
d3Zoom: s.d3Zoom,
|
d3Zoom: s.d3Zoom,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const initD3 = useStoreActions(actions => actions.initD3);
|
const initD3 = useStoreActions((actions) => actions.initD3);
|
||||||
const updateTransform = useStoreActions(actions => actions.updateTransform);
|
const updateTransform = useStoreActions((actions) => actions.updateTransform);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (zoomPane.current) {
|
if (zoomPane.current) {
|
||||||
@@ -27,7 +33,7 @@ export default (zoomPane: MutableRefObject<Element | null>, onMove: () => void,
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shiftPressed) {
|
if (selectionKeyPressed) {
|
||||||
d3ZoomInstance.on('zoom', null);
|
d3ZoomInstance.on('zoom', null);
|
||||||
} else {
|
} else {
|
||||||
d3ZoomInstance.on('zoom', () => {
|
d3ZoomInstance.on('zoom', () => {
|
||||||
@@ -37,7 +43,9 @@ export default (zoomPane: MutableRefObject<Element | null>, onMove: () => void,
|
|||||||
|
|
||||||
updateTransform(event.transform);
|
updateTransform(event.transform);
|
||||||
|
|
||||||
onMove();
|
if (onMove) {
|
||||||
|
onMove();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.d3Selection && state.d3Zoom) {
|
if (state.d3Selection && state.d3Zoom) {
|
||||||
@@ -53,5 +61,5 @@ export default (zoomPane: MutableRefObject<Element | null>, onMove: () => void,
|
|||||||
return () => {
|
return () => {
|
||||||
d3ZoomInstance.on('zoom', null);
|
d3ZoomInstance.on('zoom', null);
|
||||||
};
|
};
|
||||||
}, [shiftPressed]);
|
}, [selectionKeyPressed]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Elements, Node } from '../types';
|
|||||||
|
|
||||||
interface HookParams {
|
interface HookParams {
|
||||||
deleteKeyCode: number;
|
deleteKeyCode: number;
|
||||||
onElementsRemove: (elements: Elements) => void;
|
onElementsRemove?: (elements: Elements) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
||||||
@@ -19,7 +19,7 @@ export default ({ deleteKeyCode, onElementsRemove }: HookParams): void => {
|
|||||||
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (deleteKeyPressed && state.selectedElements) {
|
if (onElementsRemove && deleteKeyPressed && state.selectedElements) {
|
||||||
let elementsToRemove = state.selectedElements;
|
let elementsToRemove = state.selectedElements;
|
||||||
|
|
||||||
// we also want to remove the edges if only one node is selected
|
// we also want to remove the edges if only one node is selected
|
||||||
|
|||||||
+5
-4
@@ -108,7 +108,8 @@ export interface NodeComponentProps {
|
|||||||
yPos?: number;
|
yPos?: number;
|
||||||
targetPosition?: Position;
|
targetPosition?: Position;
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
onClick?: (node: Node) => void | undefined;
|
onClick?: (node: Node) => void;
|
||||||
|
onNodeDragStart?: (node: Node) => void;
|
||||||
onNodeDragStop?: (node: Node) => void;
|
onNodeDragStop?: (node: Node) => void;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
}
|
}
|
||||||
@@ -122,9 +123,9 @@ export interface WrapNodeProps {
|
|||||||
xPos: number;
|
xPos: number;
|
||||||
yPos: number;
|
yPos: number;
|
||||||
isInteractive: boolean;
|
isInteractive: boolean;
|
||||||
onClick: (node: Node) => void | undefined;
|
onClick?: (node: Node) => void;
|
||||||
onNodeDragStart: (node: Node) => void;
|
onNodeDragStart?: (node: Node) => void;
|
||||||
onNodeDragStop: (node: Node) => void;
|
onNodeDragStop?: (node: Node) => void;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
targetPosition?: Position;
|
targetPosition?: Position;
|
||||||
|
|||||||
Reference in New Issue
Block a user