Merge branch 'main' into nodesbounds
This commit is contained in:
@@ -24,7 +24,7 @@ function BackgroundComponent({
|
||||
// only used for lines and cross
|
||||
size,
|
||||
lineWidth = 1,
|
||||
offset = 2,
|
||||
offset = 0,
|
||||
color,
|
||||
bgColor,
|
||||
style,
|
||||
@@ -39,13 +39,11 @@ function BackgroundComponent({
|
||||
const gapXY: [number, number] = Array.isArray(gap) ? gap : [gap, gap];
|
||||
const scaledGap: [number, number] = [gapXY[0] * transform[2] || 1, gapXY[1] * transform[2] || 1];
|
||||
const scaledSize = patternSize * transform[2];
|
||||
const offsetXY: [number, number] = Array.isArray(offset) ? offset : [offset, offset];
|
||||
const scaledOffset: [number, number] = [offsetXY[0] * transform[2] || 1, offsetXY[1] * transform[2] || 1]
|
||||
|
||||
const patternDimensions: [number, number] = isCross ? [scaledSize, scaledSize] : scaledGap;
|
||||
|
||||
const patternOffset = isDots
|
||||
? [scaledSize / offset, scaledSize / offset]
|
||||
: [patternDimensions[0] / offset, patternDimensions[1] / offset];
|
||||
|
||||
const _patternId = `${patternId}${id ? id : ''}`;
|
||||
|
||||
return (
|
||||
@@ -69,10 +67,10 @@ function BackgroundComponent({
|
||||
width={scaledGap[0]}
|
||||
height={scaledGap[1]}
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternTransform={`translate(-${patternOffset[0]},-${patternOffset[1]})`}
|
||||
patternTransform={`translate(-${scaledOffset[0]},-${scaledOffset[1]})`}
|
||||
>
|
||||
{isDots ? (
|
||||
<DotPattern radius={scaledSize / offset} className={patternClassName} />
|
||||
<DotPattern radius={scaledSize / 2} className={patternClassName} />
|
||||
) : (
|
||||
<LinePattern
|
||||
dimensions={patternDimensions}
|
||||
|
||||
@@ -21,7 +21,7 @@ export type BackgroundProps = {
|
||||
/** Size of a single pattern element */
|
||||
size?: number;
|
||||
/** Offset of the pattern */
|
||||
offset?: number;
|
||||
offset?: number | [number, number];
|
||||
/** Line width of the Line pattern */
|
||||
lineWidth?: number;
|
||||
/** Variant of the pattern
|
||||
|
||||
@@ -43,7 +43,7 @@ export function useQueue<T>(runQueue: (items: QueueItem<T>[]) => void) {
|
||||
queue.reset();
|
||||
}
|
||||
|
||||
// Beacuse we're using reactive state to trigger this effect, we need to flip
|
||||
// Because we're using reactive state to trigger this effect, we need to flip
|
||||
// it back to false.
|
||||
setShouldFlush(false);
|
||||
}, [shouldFlush]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Reconnectable edges have a anchors around their handles to reconnect the edge.
|
||||
import { XYHandle, type Connection, EdgePosition } from '@xyflow/system';
|
||||
import { XYHandle, type Connection, EdgePosition, FinalConnectionState, HandleType } from '@xyflow/system';
|
||||
|
||||
import { EdgeAnchor } from '../Edges/EdgeAnchor';
|
||||
import type { EdgeWrapperProps, Edge } from '../../types/edges';
|
||||
@@ -9,8 +9,6 @@ type EdgeUpdateAnchorsProps<EdgeType extends Edge = Edge> = {
|
||||
edge: EdgeType;
|
||||
isReconnectable: boolean | 'source' | 'target';
|
||||
reconnectRadius: EdgeWrapperProps['reconnectRadius'];
|
||||
sourceHandleId: Edge['sourceHandle'];
|
||||
targetHandleId: Edge['targetHandle'];
|
||||
onReconnect: EdgeWrapperProps<EdgeType>['onReconnect'];
|
||||
onReconnectStart: EdgeWrapperProps<EdgeType>['onReconnectStart'];
|
||||
onReconnectEnd: EdgeWrapperProps<EdgeType>['onReconnectEnd'];
|
||||
@@ -22,8 +20,6 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
isReconnectable,
|
||||
reconnectRadius,
|
||||
edge,
|
||||
targetHandleId,
|
||||
sourceHandleId,
|
||||
sourceX,
|
||||
sourceY,
|
||||
targetX,
|
||||
@@ -38,7 +34,10 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
}: EdgeUpdateAnchorsProps<EdgeType>) {
|
||||
const store = useStoreApi();
|
||||
|
||||
const handleEdgeUpdater = (event: React.MouseEvent<SVGGElement, MouseEvent>, isSourceHandle: boolean) => {
|
||||
const handleEdgeUpdater = (
|
||||
event: React.MouseEvent<SVGGElement, MouseEvent>,
|
||||
oppositeHandle: { nodeId: string; id: string | null; type: HandleType }
|
||||
) => {
|
||||
// avoid triggering edge updater if mouse btn is not left
|
||||
if (event.button !== 0) {
|
||||
return;
|
||||
@@ -59,18 +58,14 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
panBy,
|
||||
updateConnection,
|
||||
} = store.getState();
|
||||
const nodeId = isSourceHandle ? edge.target : edge.source;
|
||||
const handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null;
|
||||
const handleType = isSourceHandle ? 'target' : 'source';
|
||||
|
||||
const isTarget = isSourceHandle;
|
||||
const isTarget = oppositeHandle.type === 'target';
|
||||
|
||||
setReconnecting(true);
|
||||
onReconnectStart?.(event, edge, handleType);
|
||||
onReconnectStart?.(event, edge, oppositeHandle.type);
|
||||
|
||||
const _onReconnectEnd = (evt: MouseEvent | TouchEvent) => {
|
||||
const _onReconnectEnd = (evt: MouseEvent | TouchEvent, connectionState: FinalConnectionState) => {
|
||||
setReconnecting(false);
|
||||
onReconnectEnd?.(evt, edge, handleType);
|
||||
onReconnectEnd?.(evt, edge, oppositeHandle.type, connectionState);
|
||||
};
|
||||
|
||||
const onConnectEdge = (connection: Connection) => onReconnect?.(edge, connection);
|
||||
@@ -80,11 +75,11 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
connectionMode,
|
||||
connectionRadius,
|
||||
domNode,
|
||||
handleId,
|
||||
nodeId,
|
||||
handleId: oppositeHandle.id,
|
||||
nodeId: oppositeHandle.nodeId,
|
||||
nodeLookup,
|
||||
isTarget,
|
||||
edgeUpdaterType: handleType,
|
||||
edgeUpdaterType: oppositeHandle.type,
|
||||
lib,
|
||||
flowId,
|
||||
cancelConnection,
|
||||
@@ -101,15 +96,15 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
};
|
||||
|
||||
const onReconnectSourceMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
|
||||
handleEdgeUpdater(event, true);
|
||||
handleEdgeUpdater(event, { nodeId: edge.target, id: edge.targetHandle ?? null, type: 'target' });
|
||||
const onReconnectTargetMouseDown = (event: React.MouseEvent<SVGGElement, MouseEvent>): void =>
|
||||
handleEdgeUpdater(event, false);
|
||||
handleEdgeUpdater(event, { nodeId: edge.source, id: edge.sourceHandle ?? null, type: 'source' });
|
||||
const onReconnectMouseEnter = () => setUpdateHover(true);
|
||||
const onReconnectMouseOut = () => setUpdateHover(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(isReconnectable === 'source' || isReconnectable === true) && (
|
||||
{(isReconnectable === true || isReconnectable === 'source') && (
|
||||
<EdgeAnchor
|
||||
position={sourcePosition}
|
||||
centerX={sourceX}
|
||||
@@ -121,7 +116,7 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
|
||||
type="source"
|
||||
/>
|
||||
)}
|
||||
{(isReconnectable === 'target' || isReconnectable === true) && (
|
||||
{(isReconnectable === true || isReconnectable === 'target') && (
|
||||
<EdgeAnchor
|
||||
position={targetPosition}
|
||||
centerX={targetX}
|
||||
|
||||
@@ -255,8 +255,6 @@ export function EdgeWrapper<EdgeType extends Edge = Edge>({
|
||||
targetPosition={targetPosition}
|
||||
setUpdateHover={setUpdateHover}
|
||||
setReconnecting={setReconnecting}
|
||||
sourceHandleId={edge.sourceHandle}
|
||||
targetHandleId={edge.targetHandle}
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
type HandleType,
|
||||
ConnectionMode,
|
||||
OnConnect,
|
||||
ConnectionState,
|
||||
Optional,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { useStore, useStoreApi } from '../../hooks/useStore';
|
||||
@@ -159,6 +161,8 @@ function HandleComponent(
|
||||
isValidConnection: isValidConnectionStore,
|
||||
lib,
|
||||
rfId: flowId,
|
||||
nodeLookup,
|
||||
connection: connectionState,
|
||||
} = store.getState();
|
||||
|
||||
if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
|
||||
@@ -187,13 +191,17 @@ function HandleComponent(
|
||||
flowId,
|
||||
doc,
|
||||
lib,
|
||||
nodeLookup,
|
||||
});
|
||||
|
||||
if (isValid && connection) {
|
||||
onConnectExtended(connection);
|
||||
}
|
||||
|
||||
onClickConnectEnd?.(event as unknown as MouseEvent);
|
||||
const connectionClone = structuredClone(connectionState) as Optional<ConnectionState, 'inProgress'>;
|
||||
delete connectionClone.inProgress;
|
||||
connectionClone.toPosition = connectionClone.toHandle ? connectionClone.toHandle.position : null;
|
||||
onClickConnectEnd?.(event as unknown as MouseEvent, connectionClone);
|
||||
|
||||
store.setState({ connectionClickStartHandle: null });
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* This component helps us to update the store with the vlues coming from the user.
|
||||
* This component helps us to update the store with the values coming from the user.
|
||||
* We distinguish between values we can update directly with `useDirectStoreUpdater` (like `snapGrid`)
|
||||
* and values that have a dedicated setter function in the store (like `setNodes`).
|
||||
*/
|
||||
|
||||
@@ -120,7 +120,6 @@ export function Pane({
|
||||
const onPointerDown = (event: ReactPointerEvent): void => {
|
||||
const { resetSelectedElements, domNode, edgeLookup } = store.getState();
|
||||
containerBounds.current = domNode?.getBoundingClientRect();
|
||||
(event.target as Element)?.setPointerCapture?.(event.pointerId);
|
||||
|
||||
if (
|
||||
!elementsSelectable ||
|
||||
@@ -132,6 +131,8 @@ export function Pane({
|
||||
return;
|
||||
}
|
||||
|
||||
(event.target as Element)?.setPointerCapture?.(event.pointerId);
|
||||
|
||||
selectionStarted.current = true;
|
||||
selectionInProgress.current = false;
|
||||
edgeIdLookup.current = new Map();
|
||||
@@ -252,9 +253,11 @@ export function Pane({
|
||||
selectionStarted.current = false;
|
||||
};
|
||||
|
||||
const draggable = panOnDrag === true || (Array.isArray(panOnDrag) && panOnDrag.includes(0));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cc(['react-flow__pane', { draggable: panOnDrag, dragging, selection: isSelecting }])}
|
||||
className={cc(['react-flow__pane', { draggable, dragging, selection: isSelecting }])}
|
||||
onClick={hasActiveSelection ? undefined : wrapHandler(onClick, container)}
|
||||
onContextMenu={wrapHandler(onContextMenu, container)}
|
||||
onWheel={wrapHandler(onWheel, container)}
|
||||
|
||||
@@ -4,17 +4,34 @@ import { ConnectionState, pointToRendererPoint } from '@xyflow/system';
|
||||
import { useStore } from './useStore';
|
||||
import type { InternalNode, Node, ReactFlowStore } from '../types';
|
||||
|
||||
const selector = (s: ReactFlowStore) => {
|
||||
function storeSelector(s: ReactFlowStore) {
|
||||
return s.connection.inProgress
|
||||
? { ...s.connection, to: pointToRendererPoint(s.connection.to, s.transform) }
|
||||
: { ...s.connection };
|
||||
};
|
||||
}
|
||||
|
||||
function getSelector<NodeType extends Node = Node, SelectorReturn = ConnectionState<InternalNode<NodeType>>>(
|
||||
connectionSelector?: (connection: ConnectionState<InternalNode<NodeType>>) => SelectorReturn
|
||||
): (s: ReactFlowStore) => SelectorReturn | ConnectionState<InternalNode> {
|
||||
if (connectionSelector) {
|
||||
const combinedSelector = (s: ReactFlowStore) => {
|
||||
const connection = storeSelector(s) as ConnectionState<InternalNode<NodeType>>;
|
||||
return connectionSelector(connection);
|
||||
};
|
||||
return combinedSelector;
|
||||
}
|
||||
|
||||
return storeSelector;
|
||||
}
|
||||
/**
|
||||
* Hook for accessing the connection state.
|
||||
*
|
||||
* @public
|
||||
* @returns ConnectionState
|
||||
*/
|
||||
export function useConnection<NodeType extends Node = Node>(): ConnectionState<InternalNode<NodeType>> {
|
||||
return useStore(selector, shallow) as ConnectionState<InternalNode<NodeType>>;
|
||||
export function useConnection<NodeType extends Node = Node, SelectorReturn = ConnectionState<InternalNode<NodeType>>>(
|
||||
connectionSelector?: (connection: ConnectionState<InternalNode<NodeType>>) => SelectorReturn
|
||||
): SelectorReturn {
|
||||
const combinedSelector = getSelector<NodeType, SelectorReturn>(connectionSelector);
|
||||
return useStore(combinedSelector, shallow) as SelectorReturn;
|
||||
}
|
||||
|
||||
@@ -258,6 +258,13 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
|
||||
|
||||
return boxToRect(box);
|
||||
},
|
||||
getHandleConnections: ({ type, id, nodeId }) =>
|
||||
Array.from(
|
||||
store
|
||||
.getState()
|
||||
.connectionLookup.get(`${nodeId}-${type}-${id ?? null}`)
|
||||
?.values() ?? []
|
||||
),
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -25,6 +25,6 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(() => updateNodeInternals(updates));
|
||||
requestAnimationFrame(() => updateNodeInternals(updates, { triggerFitView: false }));
|
||||
}, []);
|
||||
}
|
||||
|
||||
@@ -101,8 +101,16 @@ export {
|
||||
type EdgeAddChange,
|
||||
type EdgeReplaceChange,
|
||||
type KeyCode,
|
||||
type ConnectionState,
|
||||
type FinalConnectionState,
|
||||
type ConnectionInProgress,
|
||||
type NoConnection,
|
||||
} from '@xyflow/system';
|
||||
|
||||
// we need this workaround to prevent a duplicate identifier error
|
||||
import { type Handle as HandleBound } from '@xyflow/system';
|
||||
export type Handle = HandleBound;
|
||||
|
||||
// system utils
|
||||
export {
|
||||
type GetBezierPathParams,
|
||||
|
||||
@@ -77,7 +77,7 @@ const createStore = ({
|
||||
// Every node gets registerd at a ResizeObserver. Whenever a node
|
||||
// changes its dimensions, this function is called to measure the
|
||||
// new dimensions and update the nodes.
|
||||
updateNodeInternals: (updates) => {
|
||||
updateNodeInternals: (updates, params = { triggerFitView: true }) => {
|
||||
const {
|
||||
triggerNodeChanges,
|
||||
nodeLookup,
|
||||
@@ -105,23 +105,28 @@ const createStore = ({
|
||||
|
||||
updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin });
|
||||
|
||||
// we call fitView once initially after all dimensions are set
|
||||
let nextFitViewDone = fitViewDone;
|
||||
if (params.triggerFitView) {
|
||||
// we call fitView once initially after all dimensions are set
|
||||
let nextFitViewDone = fitViewDone;
|
||||
|
||||
if (!fitViewDone && fitViewOnInit) {
|
||||
nextFitViewDone = fitViewSync({
|
||||
...fitViewOnInitOptions,
|
||||
nodes: fitViewOnInitOptions?.nodes,
|
||||
});
|
||||
if (!fitViewDone && fitViewOnInit) {
|
||||
nextFitViewDone = fitViewSync({
|
||||
...fitViewOnInitOptions,
|
||||
nodes: fitViewOnInitOptions?.nodes,
|
||||
});
|
||||
}
|
||||
|
||||
// here we are cirmumventing the onNodesChange handler
|
||||
// in order to be able to display nodes even if the user
|
||||
// has not provided an onNodesChange handler.
|
||||
// Nodes are only rendered if they have a width and height
|
||||
// attribute which they get from this handler.
|
||||
set({ fitViewDone: nextFitViewDone });
|
||||
} else {
|
||||
// we always want to trigger useStore calls whenever updateNodeInternals is called
|
||||
set({});
|
||||
}
|
||||
|
||||
// here we are cirmumventing the onNodesChange handler
|
||||
// in order to be able to display nodes even if the user
|
||||
// has not provided an onNodesChange handler.
|
||||
// Nodes are only rendered if they have a width and height
|
||||
// attribute which they get from this handler.
|
||||
set({ fitViewDone: nextFitViewDone });
|
||||
|
||||
if (changes?.length > 0) {
|
||||
if (debug) {
|
||||
console.log('React Flow: trigger node changes', changes);
|
||||
@@ -276,7 +281,7 @@ const createStore = ({
|
||||
const { nodeLookup } = get();
|
||||
|
||||
for (const [, node] of nodeLookup) {
|
||||
const positionAbsolute = clampPosition(node.position, nodeExtent);
|
||||
const positionAbsolute = clampPosition(node.internals.positionAbsolute, nodeExtent);
|
||||
|
||||
nodeLookup.set(node.id, {
|
||||
...node,
|
||||
|
||||
@@ -14,6 +14,8 @@ import type {
|
||||
EdgePosition,
|
||||
StepPathOptions,
|
||||
OnError,
|
||||
ConnectionState,
|
||||
FinalConnectionState,
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { EdgeTypes, InternalNode, Node } from '.';
|
||||
@@ -78,7 +80,12 @@ export type EdgeWrapperProps<EdgeType extends Edge = Edge> = {
|
||||
onMouseLeave?: EdgeMouseHandler<EdgeType>;
|
||||
reconnectRadius?: number;
|
||||
onReconnectStart?: (event: ReactMouseEvent, edge: EdgeType, handleType: HandleType) => void;
|
||||
onReconnectEnd?: (event: MouseEvent | TouchEvent, edge: EdgeType, handleType: HandleType) => void;
|
||||
onReconnectEnd?: (
|
||||
event: MouseEvent | TouchEvent,
|
||||
edge: EdgeType,
|
||||
handleType: HandleType,
|
||||
connectionState: FinalConnectionState
|
||||
) => void;
|
||||
rfId?: string;
|
||||
edgeTypes?: EdgeTypes;
|
||||
onError?: OnError;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
import type { Rect, Viewport } from '@xyflow/system';
|
||||
import type { HandleConnection, HandleType, Rect, Viewport } from '@xyflow/system';
|
||||
import type { Node, Edge, ViewportHelperFunctions, InternalNode } from '.';
|
||||
|
||||
export type ReactFlowJsonObject<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
|
||||
@@ -181,6 +181,22 @@ export type GeneralHelpers<NodeType extends Node = Node, EdgeType extends Edge =
|
||||
* @returns the bounds of the given nodes
|
||||
*/
|
||||
getNodesBounds: (nodes: (NodeType | string)[]) => Rect;
|
||||
* Gets all connections for a given handle belonging to a specific node.
|
||||
*
|
||||
* @param type - handle type 'source' or 'target'
|
||||
* @param id - the handle id (this is only needed if you have multiple handles of the same type, meaning you have to provide a unique id for each handle)
|
||||
* @param nodeId - the node id the handle belongs to
|
||||
* @returns an array with handle connections
|
||||
*/
|
||||
getHandleConnections: ({
|
||||
type,
|
||||
id,
|
||||
nodeId,
|
||||
}: {
|
||||
type: HandleType;
|
||||
nodeId: string;
|
||||
id?: string | null;
|
||||
}) => HandleConnection[];
|
||||
};
|
||||
|
||||
export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edge = Edge> = GeneralHelpers<
|
||||
|
||||
@@ -55,7 +55,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
|
||||
nodes: NodeType[];
|
||||
nodeLookup: NodeLookup<InternalNode<NodeType>>;
|
||||
parentLookup: ParentLookup<InternalNode<NodeType>>;
|
||||
edges: Edge[];
|
||||
edges: EdgeType[];
|
||||
edgeLookup: EdgeLookup<EdgeType>;
|
||||
connectionLookup: ConnectionLookup;
|
||||
onNodesChange: OnNodesChange<NodeType> | null;
|
||||
@@ -152,7 +152,7 @@ export type ReactFlowActions<NodeType extends Node, EdgeType extends Edge> = {
|
||||
setNodes: (nodes: NodeType[]) => void;
|
||||
setEdges: (edges: EdgeType[]) => void;
|
||||
setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: EdgeType[]) => void;
|
||||
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>) => void;
|
||||
updateNodeInternals: (updates: Map<string, InternalNodeUpdate>, params?: { triggerFitView: boolean }) => void;
|
||||
updateNodePositions: UpdateNodePositions;
|
||||
resetSelectedElements: () => void;
|
||||
unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void;
|
||||
|
||||
@@ -19,10 +19,11 @@ function applyChanges(changes: any[], elements: any[]): any[] {
|
||||
// By storing a map of changes for each element, we can a quick lookup as we
|
||||
// iterate over the elements array!
|
||||
const changesMap = new Map<any, any[]>();
|
||||
const addItemChanges: any[] = [];
|
||||
|
||||
for (const change of changes) {
|
||||
if (change.type === 'add') {
|
||||
updatedElements.push(change.item);
|
||||
addItemChanges.push(change);
|
||||
continue;
|
||||
} else if (change.type === 'remove' || change.type === 'replace') {
|
||||
// For a 'remove' change we can safely ignore any other changes queued for
|
||||
@@ -73,6 +74,18 @@ function applyChanges(changes: any[], elements: any[]): any[] {
|
||||
updatedElements.push(updatedElement);
|
||||
}
|
||||
|
||||
// we need to wait for all changes to be applied before adding new items
|
||||
// to be able to add them at the correct index
|
||||
if (addItemChanges.length) {
|
||||
addItemChanges.forEach((change) => {
|
||||
if (change.index !== undefined) {
|
||||
updatedElements.splice(change.index, 0, { ...change.item });
|
||||
} else {
|
||||
updatedElements.push({ ...change.item });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return updatedElements;
|
||||
}
|
||||
|
||||
@@ -237,7 +250,7 @@ export function getElementsDiffChanges({
|
||||
const changes: any[] = [];
|
||||
const itemsLookup = new Map<string, any>(items.map((item) => [item.id, item]));
|
||||
|
||||
for (const item of items) {
|
||||
for (const [index, item] of items.entries()) {
|
||||
const lookupItem = lookup.get(item.id);
|
||||
const storeItem = lookupItem?.internals?.userNode ?? lookupItem;
|
||||
|
||||
@@ -246,7 +259,7 @@ export function getElementsDiffChanges({
|
||||
}
|
||||
|
||||
if (storeItem === undefined) {
|
||||
changes.push({ item: item, type: 'add' });
|
||||
changes.push({ item: item, type: 'add', index });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user