feat(hooks): add useOnViewportChange
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import React, { memo, FC, CSSProperties } from 'react';
|
import React, { memo, FC, CSSProperties } from 'react';
|
||||||
import { Handle, Position, NodeProps, Connection, Edge } from '@react-flow/bundle';
|
import { Handle, Position, NodeProps, Connection, Edge, useOnViewportChange } from '@react-flow/bundle';
|
||||||
|
|
||||||
const targetHandleStyle: CSSProperties = { background: '#555' };
|
const targetHandleStyle: CSSProperties = { background: '#555' };
|
||||||
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: 10 };
|
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: 10 };
|
||||||
@@ -12,6 +12,12 @@ const sourceHandleStyleB: CSSProperties = {
|
|||||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params);
|
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params);
|
||||||
|
|
||||||
const ColorSelectorNode: FC<NodeProps> = ({ data, isConnectable }) => {
|
const ColorSelectorNode: FC<NodeProps> = ({ data, isConnectable }) => {
|
||||||
|
useOnViewportChange({
|
||||||
|
onStart: (viewport) => console.log('start', viewport),
|
||||||
|
onChange: (viewport) => console.log('change', viewport),
|
||||||
|
onEnd: (viewport) => console.log('end', viewport),
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Handle type="target" position={Position.Left} style={targetHandleStyle} onConnect={onConnect} />
|
<Handle type="target" position={Position.Left} style={targetHandleStyle} onConnect={onConnect} />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { memo, useEffect } from 'react';
|
|||||||
import shallow from 'zustand/shallow';
|
import shallow from 'zustand/shallow';
|
||||||
|
|
||||||
import { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types';
|
import { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types';
|
||||||
import { useStore } from '../../hooks/useStore';
|
import { useStore, useStoreApi } from '../../hooks/useStore';
|
||||||
|
|
||||||
interface SelectionListenerProps {
|
interface SelectionListenerProps {
|
||||||
onSelectionChange: OnSelectionChangeFunc;
|
onSelectionChange: OnSelectionChangeFunc;
|
||||||
@@ -28,10 +28,14 @@ function areEqual(objA: SelectorSlice, objB: SelectorSlice) {
|
|||||||
// This is just a helper component for calling the onSelectionChange listener.
|
// This is just a helper component for calling the onSelectionChange listener.
|
||||||
// @TODO: Now that we have the onNodesChange and on EdgesChange listeners, do we still need this component?
|
// @TODO: Now that we have the onNodesChange and on EdgesChange listeners, do we still need this component?
|
||||||
function SelectionListener({ onSelectionChange }: SelectionListenerProps) {
|
function SelectionListener({ onSelectionChange }: SelectionListenerProps) {
|
||||||
|
const store = useStoreApi();
|
||||||
const { selectedNodes, selectedEdges } = useStore(selector, areEqual);
|
const { selectedNodes, selectedEdges } = useStore(selector, areEqual);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onSelectionChange({ nodes: selectedNodes, edges: selectedEdges });
|
const params = { nodes: selectedNodes, edges: selectedEdges };
|
||||||
|
|
||||||
|
onSelectionChange(params);
|
||||||
|
store.getState().onSelectionChange?.(params);
|
||||||
}, [selectedNodes, selectedEdges]);
|
}, [selectedNodes, selectedEdges]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -155,10 +155,15 @@ const ZoomPane = ({
|
|||||||
d3Zoom.on('zoom', null);
|
d3Zoom.on('zoom', null);
|
||||||
} else if (!selectionKeyPressed) {
|
} else if (!selectionKeyPressed) {
|
||||||
d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
const { onViewportChange } = store.getState();
|
||||||
|
|
||||||
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] });
|
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] });
|
||||||
if (onMove) {
|
|
||||||
|
if (onMove || onViewportChange) {
|
||||||
const flowTransform = eventToFlowTransform(event.transform);
|
const flowTransform = eventToFlowTransform(event.transform);
|
||||||
onMove(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
|
||||||
|
onViewportChange?.(flowTransform);
|
||||||
|
onMove?.(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -168,15 +173,19 @@ const ZoomPane = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (d3Zoom) {
|
if (d3Zoom) {
|
||||||
d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
const { onViewportChangeStart } = store.getState();
|
||||||
isZoomingOrPanning.current = true;
|
isZoomingOrPanning.current = true;
|
||||||
|
|
||||||
if (event.sourceEvent?.type === 'mousedown') {
|
if (event.sourceEvent?.type === 'mousedown') {
|
||||||
store.setState({ paneDragging: true });
|
store.setState({ paneDragging: true });
|
||||||
}
|
}
|
||||||
if (onMoveStart) {
|
|
||||||
|
if (onMoveStart || onViewportChangeStart) {
|
||||||
const flowTransform = eventToFlowTransform(event.transform);
|
const flowTransform = eventToFlowTransform(event.transform);
|
||||||
prevTransform.current = flowTransform;
|
prevTransform.current = flowTransform;
|
||||||
|
|
||||||
onMoveStart(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
onViewportChangeStart?.(flowTransform);
|
||||||
|
onMoveStart?.(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -185,14 +194,17 @@ const ZoomPane = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (d3Zoom) {
|
if (d3Zoom) {
|
||||||
d3Zoom.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
d3Zoom.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
const { onViewportChangeEnd } = store.getState();
|
||||||
|
|
||||||
isZoomingOrPanning.current = false;
|
isZoomingOrPanning.current = false;
|
||||||
store.setState({ paneDragging: false });
|
store.setState({ paneDragging: false });
|
||||||
|
|
||||||
if (onMoveEnd && viewChanged(prevTransform.current, event.transform)) {
|
if ((onMoveEnd || onViewportChangeEnd) && viewChanged(prevTransform.current, event.transform)) {
|
||||||
const flowTransform = eventToFlowTransform(event.transform);
|
const flowTransform = eventToFlowTransform(event.transform);
|
||||||
prevTransform.current = flowTransform;
|
prevTransform.current = flowTransform;
|
||||||
|
|
||||||
onMoveEnd(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
onViewportChangeEnd?.(flowTransform);
|
||||||
|
onMoveEnd?.(event.sourceEvent as MouseEvent | TouchEvent, flowTransform);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { useStoreApi } from './useStore';
|
||||||
|
import type { OnSelectionChangeFunc } from '../types';
|
||||||
|
|
||||||
|
export type UseOnSelectionChangeOptions = {
|
||||||
|
onChange?: OnSelectionChangeFunc;
|
||||||
|
};
|
||||||
|
|
||||||
|
function useOnSelectionChange({ onChange }: UseOnSelectionChangeOptions) {
|
||||||
|
const store = useStoreApi();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.setState({ onSelectionChange: onChange });
|
||||||
|
}, [onChange]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useOnSelectionChange;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { useStoreApi } from './useStore';
|
||||||
|
import type { OnViewportChange } from '../types';
|
||||||
|
|
||||||
|
export type UseOnViewportChangeOptions = {
|
||||||
|
onStart?: OnViewportChange;
|
||||||
|
onChange?: OnViewportChange;
|
||||||
|
onEnd?: OnViewportChange;
|
||||||
|
};
|
||||||
|
|
||||||
|
function useOnViewportChange({ onStart, onChange, onEnd }: UseOnViewportChangeOptions) {
|
||||||
|
const store = useStoreApi();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.setState({ onViewportChangeStart: onStart });
|
||||||
|
}, [onStart]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.setState({ onViewportChange: onChange });
|
||||||
|
}, [onChange]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.setState({ onViewportChangeEnd: onEnd });
|
||||||
|
}, [onEnd]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useOnViewportChange;
|
||||||
@@ -40,5 +40,6 @@ export { default as useViewport } from './hooks/useViewport';
|
|||||||
export { default as useKeyPress } from './hooks/useKeyPress';
|
export { default as useKeyPress } from './hooks/useKeyPress';
|
||||||
export * from './hooks/useNodesEdgesState';
|
export * from './hooks/useNodesEdgesState';
|
||||||
export { useStore, useStoreApi } from './hooks/useStore';
|
export { useStore, useStoreApi } from './hooks/useStore';
|
||||||
|
export { default as useOnViewportChange } from './hooks/useOnViewportChange';
|
||||||
|
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ export type UnselectNodesAndEdgesParams = {
|
|||||||
edges?: Edge[];
|
edges?: Edge[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type OnViewportChange = (viewport: Viewport) => void;
|
||||||
|
|
||||||
export interface ViewportHelperFunctions {
|
export interface ViewportHelperFunctions {
|
||||||
zoomIn: ZoomInOut;
|
zoomIn: ZoomInOut;
|
||||||
zoomOut: ZoomInOut;
|
zoomOut: ZoomInOut;
|
||||||
@@ -193,6 +195,13 @@ export type ReactFlowStore = {
|
|||||||
|
|
||||||
onNodesDelete?: OnNodesDelete;
|
onNodesDelete?: OnNodesDelete;
|
||||||
onEdgesDelete?: OnEdgesDelete;
|
onEdgesDelete?: OnEdgesDelete;
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
onViewportChangeStart?: OnViewportChange;
|
||||||
|
onViewportChange?: OnViewportChange;
|
||||||
|
onViewportChangeEnd?: OnViewportChange;
|
||||||
|
|
||||||
|
onSelectionChange?: OnSelectionChangeFunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ReactFlowActions = {
|
export type ReactFlowActions = {
|
||||||
|
|||||||
Reference in New Issue
Block a user