import { EdgeChange, NodeChange } from '@xyflow/system'; import { useStoreApi } from '../../hooks/useStore'; import { getElementsDiffChanges } from '../../utils'; import { Queue, QueueItem } from './types'; import type { Edge, Node } from '../../types'; import { useQueue } from './useQueue'; import { Accessor, createContext, JSX, useContext } from 'solid-js'; import { Writable } from '../../store/initialState'; const BatchContext = createContext<{ // eslint-disable-next-line @typescript-eslint/no-explicit-any nodeQueue: Queue; // eslint-disable-next-line @typescript-eslint/no-explicit-any edgeQueue: Queue; } | null>(null); /** * This is a context provider that holds and processes the node and edge update queues * that are needed to handle setNodes, addNodes, setEdges and addEdges. * * @internal */ export function BatchProvider(p: { children: JSX.Element; }) { const store = useStoreApi(); const nodeQueueHandler = (queueItems: QueueItem[]) => { const { nodes, setNodes, hasDefaultNodes, onNodesChange: getOnNodesChange, nodeLookup } = store; // This is essentially an `Array.reduce` in imperative clothing. Processing // this queue is a relatively hot path so we'd like to avoid the overhead of // array methods where we can. let next = nodes.get(); for (const payload of queueItems) { next = typeof payload === 'function' ? payload(next) : payload; } const onNodesChange = getOnNodesChange.get(); if (hasDefaultNodes.get()) { setNodes(next); } else if (onNodesChange) { onNodesChange( getElementsDiffChanges({ items: next, lookup: nodeLookup, }) as NodeChange[] ); } }; const nodeQueue = useQueue(nodeQueueHandler); const edgeQueueHandler = (queueItems: QueueItem[]) => { const { edges, setEdges, hasDefaultEdges, onEdgesChange: getOnEdgesChange, edgeLookup } = store; let next = edges.get() as EdgeType[]; for (const payload of queueItems) { next = typeof payload === 'function' ? payload(next) : payload; } const onEdgesChange = getOnEdgesChange.get(); if (hasDefaultEdges.get()) { setEdges(next); } else if (onEdgesChange) { onEdgesChange( getElementsDiffChanges({ items: next, lookup: edgeLookup, }) as EdgeChange[] ); } }; const edgeQueue = useQueue(edgeQueueHandler); const value = { nodeQueue, edgeQueue }; return {p.children}; } export function useBatchContext() { const batchContext = useContext(BatchContext); if (!batchContext) { throw new Error('useBatchContext must be used within a BatchProvider'); } return batchContext; }