initial version of middlewares
This commit is contained in:
@@ -28,7 +28,15 @@ export function BatchProvider<NodeType extends Node = Node, EdgeType extends Edg
|
||||
const store = useStoreApi<NodeType, EdgeType>();
|
||||
|
||||
const nodeQueueHandler = useCallback((queueItems: QueueItem<NodeType>[]) => {
|
||||
const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup, fitViewQueued } = store.getState();
|
||||
const {
|
||||
nodes = [],
|
||||
setNodes,
|
||||
hasDefaultNodes,
|
||||
onNodesChange,
|
||||
nodeLookup,
|
||||
fitViewQueued,
|
||||
nodeChangeMiddleware,
|
||||
} = store.getState();
|
||||
|
||||
/*
|
||||
* This is essentially an `Array.reduce` in imperative clothing. Processing
|
||||
@@ -40,11 +48,23 @@ export function BatchProvider<NodeType extends Node = Node, EdgeType extends Edg
|
||||
next = typeof payload === 'function' ? payload(next) : payload;
|
||||
}
|
||||
|
||||
const changes = getElementsDiffChanges({
|
||||
let changes = getElementsDiffChanges({
|
||||
items: next,
|
||||
lookup: nodeLookup,
|
||||
}) as NodeChange<NodeType>[];
|
||||
|
||||
console.log('this workds');
|
||||
|
||||
for (const middleware of nodeChangeMiddleware.values()) {
|
||||
changes = middleware(changes);
|
||||
}
|
||||
|
||||
// for (const middleware of nodeSyncMiddleware.values()) {
|
||||
// changes = middleware(changes);
|
||||
// }
|
||||
|
||||
// Do we always want to setNodes(next) or only when there are changes?
|
||||
|
||||
if (hasDefaultNodes) {
|
||||
setNodes(next);
|
||||
}
|
||||
|
||||
97
packages/react/src/hooks/useMiddleware.ts
Normal file
97
packages/react/src/hooks/useMiddleware.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { NodeChange } from '@xyflow/system';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useStoreApi } from './useStore';
|
||||
import { Edge, Node } from '../types';
|
||||
|
||||
/**
|
||||
* We identify each middleware with a symbol that is unique for each hook instance.
|
||||
*/
|
||||
|
||||
function useSymbol() {
|
||||
const symbol = useRef<symbol>();
|
||||
if (!symbol.current) {
|
||||
symbol.current = Symbol();
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
export function useNodeChangeMiddleware<NodeType extends Node = Node>(
|
||||
fn: (changes: NodeChange<NodeType>[]) => NodeChange<NodeType>[]
|
||||
) {
|
||||
const store = useStoreApi<NodeType, Edge>();
|
||||
const symbol = useSymbol();
|
||||
|
||||
useEffect(() => {
|
||||
const { nodeChangeMiddleware } = store.getState();
|
||||
nodeChangeMiddleware.set(symbol.current!, fn);
|
||||
}, [fn]);
|
||||
|
||||
useEffect(() => {
|
||||
const { nodeChangeMiddleware } = store.getState();
|
||||
return () => {
|
||||
nodeChangeMiddleware.delete(symbol.current!);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
export function useNodeChangeMiddlewareDynamic<NodeType extends Node = Node>(
|
||||
fn: (changes: NodeChange<NodeType>[]) => NodeChange<NodeType>[]
|
||||
) {
|
||||
const store = useStoreApi<NodeType, Edge>();
|
||||
const symbol = useSymbol();
|
||||
|
||||
const { nodeChangeMiddleware } = store.getState();
|
||||
nodeChangeMiddleware.delete(symbol.current!);
|
||||
nodeChangeMiddleware.set(symbol.current!, fn);
|
||||
}
|
||||
|
||||
// export function useEdgeChangeMiddleware(fn: (changes: EdgeChange[]) => EdgeChange[]) {
|
||||
// const store = useStoreApi();
|
||||
// const symbol = useSymbol();
|
||||
|
||||
// useEffect(() => {
|
||||
// const { edgeChangeMiddleware } = store.getState();
|
||||
// edgeChangeMiddleware.set(symbol.current!, fn);
|
||||
// }, [fn]);
|
||||
|
||||
// useEffect(() => {
|
||||
// const { edgeChangeMiddleware } = store.getState();
|
||||
// return () => {
|
||||
// edgeChangeMiddleware.delete(symbol.current!);
|
||||
// };
|
||||
// }, []);
|
||||
// }
|
||||
|
||||
// export function useNodeSyncMiddleware(fn: (changes: NodeChange[]) => NodeChange[]) {
|
||||
// const store = useStoreApi();
|
||||
// const symbol = useSymbol();
|
||||
|
||||
// useEffect(() => {
|
||||
// const { nodeSyncMiddleware } = store.getState();
|
||||
// nodeSyncMiddleware.set(symbol.current!, fn);
|
||||
// }, [fn]);
|
||||
|
||||
// useEffect(() => {
|
||||
// const { nodeSyncMiddleware } = store.getState();
|
||||
// return () => {
|
||||
// nodeSyncMiddleware.delete(symbol.current!);
|
||||
// };
|
||||
// }, []);
|
||||
// }
|
||||
|
||||
// export function useEdgeSyncMiddleware(fn: (changes: EdgeChange[]) => EdgeChange[]) {
|
||||
// const store = useStoreApi();
|
||||
// const symbol = useSymbol();
|
||||
|
||||
// useEffect(() => {
|
||||
// const { edgeSyncMiddleware } = store.getState();
|
||||
// edgeSyncMiddleware.set(symbol.current!, fn);
|
||||
// }, [fn]);
|
||||
|
||||
// useEffect(() => {
|
||||
// const { edgeSyncMiddleware } = store.getState();
|
||||
// return () => {
|
||||
// edgeSyncMiddleware.delete(symbol.current!);
|
||||
// };
|
||||
// }, []);
|
||||
// }
|
||||
@@ -30,6 +30,8 @@ export { useConnection } from './hooks/useConnection';
|
||||
export { useInternalNode } from './hooks/useInternalNode';
|
||||
export { useNodeId } from './contexts/NodeIdContext';
|
||||
|
||||
export { useNodeChangeMiddleware, useNodeChangeMiddlewareDynamic } from './hooks/useMiddleware';
|
||||
|
||||
export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
|
||||
export { isNode, isEdge } from './utils/general';
|
||||
|
||||
|
||||
@@ -175,8 +175,8 @@ const createStore = ({
|
||||
},
|
||||
updateNodePositions: (nodeDragItems, dragging = false) => {
|
||||
const parentExpandChildren: ParentExpandChild[] = [];
|
||||
const changes = [];
|
||||
const { nodeLookup, triggerNodeChanges } = get();
|
||||
let changes = [];
|
||||
const { nodeLookup, triggerNodeChanges, nodeChangeMiddleware } = get();
|
||||
|
||||
for (const [id, dragItem] of nodeDragItems) {
|
||||
// we are using the nodelookup to be sure to use the current expandParent and parentId value
|
||||
@@ -216,6 +216,10 @@ const createStore = ({
|
||||
changes.push(...parentExpandChanges);
|
||||
}
|
||||
|
||||
for (const middleware of nodeChangeMiddleware.values()) {
|
||||
changes = middleware(changes);
|
||||
}
|
||||
|
||||
triggerNodeChanges(changes);
|
||||
},
|
||||
triggerNodeChanges: (changes) => {
|
||||
|
||||
@@ -146,6 +146,11 @@ const getInitialState = ({
|
||||
lib: 'react',
|
||||
debug: false,
|
||||
ariaLabelConfig: defaultAriaLabelConfig,
|
||||
|
||||
nodeChangeMiddleware: new Map(),
|
||||
edgeChangeMiddleware: new Map(),
|
||||
nodeSyncMiddleware: new Map(),
|
||||
edgeSyncMiddleware: new Map(),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -152,6 +152,11 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
|
||||
lib: string;
|
||||
debug: boolean;
|
||||
ariaLabelConfig: AriaLabelConfig;
|
||||
|
||||
nodeChangeMiddleware: Map<symbol, (changes: NodeChange<NodeType>[]) => NodeChange<NodeType>[]>;
|
||||
edgeChangeMiddleware: Map<symbol, (changes: EdgeChange<EdgeType>[]) => EdgeChange<EdgeType>[]>;
|
||||
nodeSyncMiddleware: Map<symbol, (changes: NodeChange<NodeType>[]) => NodeChange<NodeType>[]>;
|
||||
edgeSyncMiddleware: Map<symbol, (changes: EdgeChange<EdgeType>[]) => EdgeChange<EdgeType>[]>;
|
||||
};
|
||||
|
||||
export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
||||
|
||||
Reference in New Issue
Block a user