diff --git a/examples/react/src/examples/Layouting/index.tsx b/examples/react/src/examples/Layouting/index.tsx
index 7383e41e..2371b503 100644
--- a/examples/react/src/examples/Layouting/index.tsx
+++ b/examples/react/src/examples/Layouting/index.tsx
@@ -19,6 +19,7 @@ import {
import initialItems from './initial-elements';
import styles from './layouting.module.css';
+import ReactFlowDevTools from '../DevTools/DevTools';
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
@@ -98,6 +99,7 @@ const LayoutFlow = () => {
onEdgesChange={onEdgesChange}
>
+
diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md
index acba7b99..2fd7bf5d 100644
--- a/packages/react/CHANGELOG.md
+++ b/packages/react/CHANGELOG.md
@@ -5,6 +5,9 @@
## Patch changes
- fix hidden nodes
+- use `direction=ltr` for outer wrapper to support rtl sites
+- allow pinch zoom even if `preventScrolling=false`
+- export node and edge change related types
## 12.0.0-next.13
diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx
index e081a6c7..18c2d314 100644
--- a/packages/react/src/components/NodeWrapper/index.tsx
+++ b/packages/react/src/components/NodeWrapper/index.tsx
@@ -123,7 +123,7 @@ export function NodeWrapper({
if (targetPosChanged) {
prevTargetPosition.current = node.targetPosition;
}
- store.getState().updateNodeDimensions(new Map([[id, { id, nodeElement: nodeRef.current, force: true }]]));
+ store.getState().updateNodeInternals(new Map([[id, { id, nodeElement: nodeRef.current, force: true }]]));
}
}, [id, nodeType, node.sourcePosition, node.targetPosition]);
diff --git a/packages/react/src/container/NodeRenderer/useResizeObserver.ts b/packages/react/src/container/NodeRenderer/useResizeObserver.ts
index 82c079bd..fa7d501f 100644
--- a/packages/react/src/container/NodeRenderer/useResizeObserver.ts
+++ b/packages/react/src/container/NodeRenderer/useResizeObserver.ts
@@ -2,12 +2,12 @@ import { useEffect, useMemo, useRef } from 'react';
import { ReactFlowState } from '../../types';
import { useStore } from '../../hooks/useStore';
-import { NodeDimensionUpdate } from '@xyflow/system';
+import { InternalNodeUpdate } from '@xyflow/system';
-const selector = (s: ReactFlowState) => s.updateNodeDimensions;
+const selector = (s: ReactFlowState) => s.updateNodeInternals;
export function useResizeObserver() {
- const updateNodeDimensions = useStore(selector);
+ const updateNodeInternals = useStore(selector);
const resizeObserverRef = useRef();
const resizeObserver = useMemo(() => {
@@ -16,7 +16,7 @@ export function useResizeObserver() {
}
const observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
- const updates = new Map();
+ const updates = new Map();
entries.forEach((entry: ResizeObserverEntry) => {
const id = entry.target.getAttribute('data-id') as string;
@@ -26,7 +26,7 @@ export function useResizeObserver() {
});
});
- updateNodeDimensions(updates);
+ updateNodeInternals(updates);
});
resizeObserverRef.current = observer;
diff --git a/packages/react/src/hooks/useUpdateNodeInternals.ts b/packages/react/src/hooks/useUpdateNodeInternals.ts
index b156d506..63965d72 100644
--- a/packages/react/src/hooks/useUpdateNodeInternals.ts
+++ b/packages/react/src/hooks/useUpdateNodeInternals.ts
@@ -1,5 +1,5 @@
import { useCallback } from 'react';
-import type { UpdateNodeInternals, NodeDimensionUpdate } from '@xyflow/system';
+import type { UpdateNodeInternals, InternalNodeUpdate } from '@xyflow/system';
import { useStoreApi } from '../hooks/useStore';
@@ -13,9 +13,9 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
const store = useStoreApi();
return useCallback((id: string | string[]) => {
- const { domNode, updateNodeDimensions } = store.getState();
+ const { domNode, updateNodeInternals } = store.getState();
const updateIds = Array.isArray(id) ? id : [id];
- const updates = new Map();
+ const updates = new Map();
updateIds.forEach((updateId) => {
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`) as HTMLDivElement;
@@ -25,6 +25,6 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
}
});
- requestAnimationFrame(() => updateNodeDimensions(updates));
+ requestAnimationFrame(() => updateNodeInternals(updates));
}, []);
}
diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts
index 492d6186..7ce263c9 100644
--- a/packages/react/src/store/index.ts
+++ b/packages/react/src/store/index.ts
@@ -5,7 +5,7 @@ import {
adoptUserNodes,
updateAbsolutePositions,
panBy as panBySystem,
- updateNodeDimensions as updateNodeDimensionsSystem,
+ updateNodeInternals as updateNodeInternalsSystem,
updateConnectionLookup,
handleParentExpand,
NodeChange,
@@ -71,7 +71,7 @@ const createRFStore = ({
// 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.
- updateNodeDimensions: (updates) => {
+ updateNodeInternals: (updates) => {
const {
onNodesChange,
fitView,
@@ -84,9 +84,9 @@ const createRFStore = ({
debug,
} = get();
- const changes = updateNodeDimensionsSystem(updates, nodeLookup, domNode, nodeOrigin);
+ const { changes, updatedInternals } = updateNodeInternalsSystem(updates, nodeLookup, domNode, nodeOrigin);
- if (changes.length === 0) {
+ if (!updatedInternals) {
return;
}
diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts
index 416f56f3..397ca6f1 100644
--- a/packages/react/src/types/store.ts
+++ b/packages/react/src/types/store.ts
@@ -2,7 +2,7 @@ import {
ConnectionMode,
type ConnectionStatus,
type CoordinateExtent,
- type NodeDimensionUpdate,
+ type InternalNodeUpdate,
type UpdateNodePositions,
type NodeOrigin,
type OnConnect,
@@ -154,7 +154,7 @@ export type ReactFlowActions = {
setNodes: (nodes: NodeType[]) => void;
setEdges: (edges: EdgeType[]) => void;
setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: EdgeType[]) => void;
- updateNodeDimensions: (updates: Map) => void;
+ updateNodeInternals: (updates: Map) => void;
updateNodePositions: UpdateNodePositions;
resetSelectedElements: () => void;
unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void;
diff --git a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte
index a466d0ad..384b3369 100644
--- a/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte
+++ b/packages/svelte/src/lib/components/NodeWrapper/NodeWrapper.svelte
@@ -52,7 +52,7 @@
nodeDragThreshold,
selectNodesOnDrag,
handleNodeSelection,
- updateNodeDimensions
+ updateNodeInternals
} = store;
let nodeRef: HTMLDivElement;
@@ -97,7 +97,7 @@
if (doUpdate) {
requestAnimationFrame(() =>
- updateNodeDimensions(
+ updateNodeInternals(
new Map([
[
id,
diff --git a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte
index ae400eb5..c0b8165e 100644
--- a/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte
+++ b/packages/svelte/src/lib/container/NodeRenderer/NodeRenderer.svelte
@@ -10,7 +10,7 @@
nodesDraggable,
nodesConnectable,
elementsSelectable,
- updateNodeDimensions
+ updateNodeInternals
} = useStore();
const resizeObserver: ResizeObserver | null =
@@ -29,7 +29,7 @@
});
});
- updateNodeDimensions(updates);
+ updateNodeInternals(updates);
});
onDestroy(() => {
diff --git a/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts b/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts
index 45a203eb..cbb240ab 100644
--- a/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts
+++ b/packages/svelte/src/lib/hooks/useUpdateNodeInternals.ts
@@ -10,7 +10,7 @@ import { useStore } from '$lib/store';
* @returns function for updating node internals
*/
export function useUpdateNodeInternals(): UpdateNodeInternals {
- const { domNode, updateNodeDimensions } = useStore();
+ const { domNode, updateNodeInternals } = useStore();
// @todo: do we want to add this to system?
const updateInternals = (id: string | string[]) => {
@@ -27,7 +27,7 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
}
});
- requestAnimationFrame(() => updateNodeDimensions(updates));
+ requestAnimationFrame(() => updateNodeInternals(updates));
};
return updateInternals;
diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts
index 2f6266eb..c808d2af 100644
--- a/packages/svelte/src/lib/store/index.ts
+++ b/packages/svelte/src/lib/store/index.ts
@@ -5,10 +5,10 @@ import {
fitView as fitViewUtil,
getElementsToRemove,
panBy as panBySystem,
- updateNodeDimensions as updateNodeDimensionsSystem,
+ updateNodeInternals as updateNodeInternalsSystem,
addEdge as addEdgeUtil,
type UpdateNodePositions,
- type NodeDimensionUpdate,
+ type InternalNodeUpdate,
type ViewportHelperFunctionOptions,
type Connection,
type XYPosition,
@@ -78,16 +78,16 @@ export function createStore({
store.nodes.update((nds) => nds);
};
- function updateNodeDimensions(updates: Map) {
+ function updateNodeInternals(updates: Map) {
const nodeLookup = get(store.nodeLookup);
- const changes = updateNodeDimensionsSystem(
+ const { changes, updatedInternals } = updateNodeInternalsSystem(
updates,
nodeLookup,
get(store.domNode),
get(store.nodeOrigin)
);
- if (!changes) {
+ if (!updatedInternals) {
return;
}
@@ -400,7 +400,7 @@ export function createStore({
setEdgeTypes,
addEdge,
updateNodePositions,
- updateNodeDimensions,
+ updateNodeInternals,
zoomIn,
zoomOut,
fitView: (options?: FitViewOptions) => fitView(options),
diff --git a/packages/svelte/src/lib/store/types.ts b/packages/svelte/src/lib/store/types.ts
index 8d41d63f..d87ca907 100644
--- a/packages/svelte/src/lib/store/types.ts
+++ b/packages/svelte/src/lib/store/types.ts
@@ -1,6 +1,6 @@
import type { Writable } from 'svelte/store';
import type {
- NodeDimensionUpdate,
+ InternalNodeUpdate,
XYPosition,
ViewportHelperFunctionOptions,
Connection,
@@ -27,7 +27,7 @@ export type SvelteFlowStoreActions = {
setTranslateExtent: (extent: CoordinateExtent) => void;
fitView: (options?: FitViewOptions) => boolean;
updateNodePositions: UpdateNodePositions;
- updateNodeDimensions: (updates: Map) => void;
+ updateNodeInternals: (updates: Map) => void;
unselectNodesAndEdges: (params?: { nodes?: Node[]; edges?: Edge[] }) => void;
addSelectedNodes: (ids: string[]) => void;
addSelectedEdges: (ids: string[]) => void;
diff --git a/packages/system/src/types/nodes.ts b/packages/system/src/types/nodes.ts
index c8c85a55..d802dad8 100644
--- a/packages/system/src/types/nodes.ts
+++ b/packages/system/src/types/nodes.ts
@@ -105,7 +105,7 @@ export type NodeHandleBounds = {
target: HandleElement[] | null;
};
-export type NodeDimensionUpdate = {
+export type InternalNodeUpdate = {
id: string;
nodeElement: HTMLDivElement;
force?: boolean;
diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts
index 38a01b76..0d7f2645 100644
--- a/packages/system/src/utils/store.ts
+++ b/packages/system/src/utils/store.ts
@@ -1,7 +1,7 @@
import {
NodeBase,
CoordinateExtent,
- NodeDimensionUpdate,
+ InternalNodeUpdate,
NodeOrigin,
PanZoomInstance,
Transform,
@@ -11,7 +11,6 @@ import {
EdgeBase,
EdgeLookup,
InternalNodeBase,
- NodeChange,
NodeLookup,
Rect,
NodeDimensionChange,
@@ -213,16 +212,17 @@ export function handleParentExpand(
return changes;
}
-export function updateNodeDimensions(
- updates: Map,
+export function updateNodeInternals(
+ updates: Map,
nodeLookup: Map,
domNode: HTMLElement | null,
nodeOrigin?: NodeOrigin
-): (NodeDimensionChange | NodePositionChange)[] {
+): { changes: (NodeDimensionChange | NodePositionChange)[]; updatedInternals: boolean } {
const viewportNode = domNode?.querySelector('.xyflow__viewport');
+ let updatedInternals = false;
if (!viewportNode) {
- return [];
+ return { changes: [], updatedInternals };
}
const changes: (NodeDimensionChange | NodePositionChange)[] = [];
@@ -242,24 +242,20 @@ export function updateNodeDimensions(
handleBounds: undefined,
},
});
+ updatedInternals = true;
} else if (node) {
const dimensions = getDimensions(update.nodeElement);
+ const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
const doUpdate = !!(
dimensions.width &&
dimensions.height &&
- (node.measured?.width !== dimensions.width ||
- node.measured?.height !== dimensions.height ||
- !node.internals.handleBounds ||
- update.force)
+ (dimensionChanged || !node.internals.handleBounds || update.force)
);
if (doUpdate) {
const newNode = {
...node,
- measured: {
- ...node.measured,
- ...dimensions,
- },
+ measured: dimensions,
internals: {
...node.internals,
handleBounds: {
@@ -270,15 +266,18 @@ export function updateNodeDimensions(
};
nodeLookup.set(node.id, newNode);
+ updatedInternals = true;
- changes.push({
- id: newNode.id,
- type: 'dimensions',
- dimensions,
- });
+ if (dimensionChanged) {
+ changes.push({
+ id: newNode.id,
+ type: 'dimensions',
+ dimensions,
+ });
- if (newNode.expandParent) {
- triggerChangeNodes.push(newNode);
+ if (newNode.expandParent) {
+ triggerChangeNodes.push(newNode);
+ }
}
}
}
@@ -289,7 +288,7 @@ export function updateNodeDimensions(
changes.push(...parentExpandChanges);
}
- return changes;
+ return { changes, updatedInternals };
}
export function panBy({