From 388b2588a4350e4a9e04680e3327c91d18b0fcea Mon Sep 17 00:00:00 2001 From: Nick Lawrence Date: Fri, 4 Apr 2025 16:05:39 -0400 Subject: [PATCH 01/40] When horizontal, remove the border from all control buttons --- packages/system/src/styles/style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/system/src/styles/style.css b/packages/system/src/styles/style.css index cb6f2b7c..5e767630 100644 --- a/packages/system/src/styles/style.css +++ b/packages/system/src/styles/style.css @@ -158,4 +158,8 @@ &-button:last-child { border-bottom: none; } + + &.horizontal &-button { + border-bottom: none; + } } From 20fcba300fb78dd17a1420b290af2e724614d3bd Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 9 Apr 2025 14:04:31 +0200 Subject: [PATCH 02/40] fix legacy padding --- packages/system/src/utils/general.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 67743b5d..bae2ea57 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -184,7 +184,7 @@ export const rendererPointToPoint = ({ x, y }: XYPosition, [tx, ty, tScale]: Tra */ function parsePadding(padding: PaddingWithUnit, viewport: number): number { if (typeof padding === 'number') { - return Math.floor(viewport - viewport / (1 + padding)); + return Math.floor((viewport - viewport / (1 + padding)) * 0.5); } if (typeof padding === 'string' && padding.endsWith('px')) { From e5735b514a54d86ba0ca7bd725e8bfead89fc08e Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 9 Apr 2025 14:06:20 +0200 Subject: [PATCH 03/40] add changeset --- .changeset/thin-geese-hope.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/thin-geese-hope.md diff --git a/.changeset/thin-geese-hope.md b/.changeset/thin-geese-hope.md new file mode 100644 index 00000000..47dd18be --- /dev/null +++ b/.changeset/thin-geese-hope.md @@ -0,0 +1,7 @@ +--- +'@xyflow/system': patch +'@xyflow/react': patch +'@xyflow/svelte': patch +--- + +Fix legacy padding being slightly larger than before From be4e266d69734b7e656a4354d2275e3b0198cd36 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 9 Apr 2025 14:20:11 +0200 Subject: [PATCH 04/40] use nodesInitialized from adoptUserNodes --- packages/react/src/hooks/useNodesInitialized.ts | 12 +++++++----- packages/react/src/store/index.ts | 4 ++-- packages/react/src/store/initialState.ts | 3 ++- packages/react/src/types/store.ts | 1 + packages/system/src/utils/store.ts | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/react/src/hooks/useNodesInitialized.ts b/packages/react/src/hooks/useNodesInitialized.ts index a44ab658..6fd042a5 100644 --- a/packages/react/src/hooks/useNodesInitialized.ts +++ b/packages/react/src/hooks/useNodesInitialized.ts @@ -9,15 +9,17 @@ export type UseNodesInitializedOptions = { }; const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) => { + if (!options.includeHiddenNodes) { + return s.nodesInitialized; + } + if (s.nodeLookup.size === 0) { return false; } - for (const [, { hidden, internals }] of s.nodeLookup) { - if (options.includeHiddenNodes || !hidden) { - if (internals.handleBounds === undefined || !nodeHasDimensions(internals.userNode)) { - return false; - } + for (const [, { internals }] of s.nodeLookup) { + if (internals.handleBounds === undefined || !nodeHasDimensions(internals.userNode)) { + return false; } } diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 924e83cf..7682dc90 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -91,9 +91,9 @@ const createStore = ({ if (fitViewQueued && nodesInitialized) { resolveFitView(); - set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + set({ nodes, nodesInitialized, fitViewQueued: false, fitViewOptions: undefined }); } else { - set({ nodes }); + set({ nodes, nodesInitialized }); } }, setEdges: (edges: Edge[]) => { diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index 8be408b8..996cc148 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -46,7 +46,7 @@ const getInitialState = ({ const storeNodeExtent = nodeExtent ?? infiniteExtent; updateConnectionLookup(connectionLookup, edgeLookup, storeEdges); - adoptUserNodes(storeNodes, nodeLookup, parentLookup, { + const nodesInitialized = adoptUserNodes(storeNodes, nodeLookup, parentLookup, { nodeOrigin: storeNodeOrigin, nodeExtent: storeNodeExtent, elevateNodesOnSelect: false, @@ -69,6 +69,7 @@ const getInitialState = ({ height: 0, transform, nodes: storeNodes, + nodesInitialized, nodeLookup, parentLookup, edges: storeEdges, diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index efd9d957..347eb8b1 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -53,6 +53,7 @@ export type ReactFlowStore>; parentLookup: ParentLookup>; edges: EdgeType[]; diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 14fc710a..1546a8ff 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -88,7 +88,7 @@ export function adoptUserNodes( ): boolean { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); - let nodesInitialized = true; + let nodesInitialized = nodes.length > 0; const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; From fc241253d5dba35f5febf411e77dbc5acb91d5d7 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 9 Apr 2025 14:21:29 +0200 Subject: [PATCH 05/40] add changeset --- .changeset/giant-pets-draw.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/giant-pets-draw.md diff --git a/.changeset/giant-pets-draw.md b/.changeset/giant-pets-draw.md new file mode 100644 index 00000000..df1e03a2 --- /dev/null +++ b/.changeset/giant-pets-draw.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/system': patch +--- + +Optimize performance of nodesInitialized From 0993c2c0af263c201f3e18ab27a2bc050772754e Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 10 Apr 2025 11:25:39 +0200 Subject: [PATCH 06/40] chore(marker): add aria-hidden true #5190 --- packages/react/src/components/Attribution/index.tsx | 1 + packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/Attribution/index.tsx b/packages/react/src/components/Attribution/index.tsx index eb69bd13..813aaf02 100644 --- a/packages/react/src/components/Attribution/index.tsx +++ b/packages/react/src/components/Attribution/index.tsx @@ -17,6 +17,7 @@ export function Attribution({ proOptions, position = 'bottom-right' }: Attributi position={position} className="react-flow__attribution" data-message="Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev" + aria-hidden="true" > React Flow diff --git a/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx b/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx index 17b5950c..1c12775d 100644 --- a/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx +++ b/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx @@ -67,7 +67,7 @@ const MarkerDefinitions = ({ defaultColor, rfId }: MarkerDefinitionsProps) => { } return ( - +
- -
- + ); }; -export default WrappedFlow; +export default Flow; diff --git a/packages/react/src/components/SelectionListener/index.tsx b/packages/react/src/components/SelectionListener/index.tsx index 04c46416..89ed2c26 100644 --- a/packages/react/src/components/SelectionListener/index.tsx +++ b/packages/react/src/components/SelectionListener/index.tsx @@ -19,13 +19,13 @@ const selector = (s: ReactFlowState) => { const selectedEdges = []; for (const [, node] of s.nodeLookup) { - if (node.selected && (s.elementsSelectable || node.selectable)) { + if (node.selected) { selectedNodes.push(node.internals.userNode); } } for (const [, edge] of s.edgeLookup) { - if (edge.selected && (s.elementsSelectable || edge.selectable)) { + if (edge.selected) { selectedEdges.push(edge); } } diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 7682dc90..e2fedee3 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -297,7 +297,11 @@ const createStore = ({ get().panZoom?.setClickDistance(clickDistance); }, resetSelectedElements: () => { - const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get(); + const { edges, nodes, triggerNodeChanges, triggerEdgeChanges, elementsSelectable } = get(); + + if (!elementsSelectable) { + return; + } const nodeChanges = nodes.reduce( (res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), From bce74e8811a98c967b5bd06c3e5aecde24c8b679 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 08:25:55 +0200 Subject: [PATCH 19/40] chore(changeset): add --- .changeset/flat-crabs-attack.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/flat-crabs-attack.md diff --git a/.changeset/flat-crabs-attack.md b/.changeset/flat-crabs-attack.md new file mode 100644 index 00000000..2d23f9cb --- /dev/null +++ b/.changeset/flat-crabs-attack.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Keep node seleciton on pane click if elementsSelectable=false From c9415969eb459992755cd063490c6c80fa47afd2 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 13:06:49 +0200 Subject: [PATCH 20/40] feat(provider): add minZoom, maxZoom and fitViewOptions --- .../components/ReactFlowProvider/index.tsx | 39 ++++++++++++++++++- .../react/src/container/ReactFlow/Wrapper.tsx | 11 +++++- .../react/src/container/ReactFlow/index.tsx | 3 ++ packages/react/src/store/index.ts | 23 ++++++++++- packages/react/src/store/initialState.ts | 23 ++++++++--- 5 files changed, 90 insertions(+), 9 deletions(-) diff --git a/packages/react/src/components/ReactFlowProvider/index.tsx b/packages/react/src/components/ReactFlowProvider/index.tsx index 1492ca3f..74f19f81 100644 --- a/packages/react/src/components/ReactFlowProvider/index.tsx +++ b/packages/react/src/components/ReactFlowProvider/index.tsx @@ -3,18 +3,49 @@ import { useState, type ReactNode } from 'react'; import { Provider } from '../../contexts/StoreContext'; import { createStore } from '../../store'; import { BatchProvider } from '../BatchProvider'; -import type { Node, Edge } from '../../types'; +import type { Node, Edge, FitViewOptions } from '../../types'; import { CoordinateExtent, NodeOrigin } from '@xyflow/system'; export type ReactFlowProviderProps = { + /** These nodes are used to initialize the flow. They are not dynamic. */ initialNodes?: Node[]; + /** These edges are used to initialize the flow. They are not dynamic. */ initialEdges?: Edge[]; + /** These nodes are used to initialize the flow. They are not dynamic. */ defaultNodes?: Node[]; + /** These edges are used to initialize the flow. They are not dynamic. */ defaultEdges?: Edge[]; + /** The initial width is necessary to be able to use fitView on the server */ initialWidth?: number; + /** The initial height is necessary to be able to use fitView on the server */ initialHeight?: number; + /** When `true`, the flow will be zoomed and panned to fit all the nodes initially provided. */ fitView?: boolean; + /** + * You can provide an object of options to customize the fitView behavior. + */ + fitViewOptions?: FitViewOptions; + /** Initial minimum zoom level */ + initialMinZoom?: number; + /** Initial maximum zoom level */ + initialMaxZoom?: number; + /** + * The origin of the node to use when placing it in the flow or looking up its `x` and `y` + * position. An origin of `[0, 0]` means that a node's top left corner will be placed at the `x` + * and `y` position. + * @default [0, 0] + * @example + * [0, 0] // default, top left + * [0.5, 0.5] // center + * [1, 1] // bottom right + */ nodeOrigin?: NodeOrigin; + /** + * By default, nodes can be placed on an infinite flow. You can use this prop to set a boundary. + * + * The first pair of coordinates is the top left boundary and the second pair is the bottom right. + * @example [[-1000, -10000], [1000, 1000]] + */ nodeExtent?: CoordinateExtent; children: ReactNode; }; @@ -60,6 +91,9 @@ export function ReactFlowProvider({ defaultEdges, initialWidth: width, initialHeight: height, + initialMinZoom: minZoom, + initialMaxZoom: maxZoom, + fitViewOptions, fitView, nodeOrigin, nodeExtent, @@ -74,6 +108,9 @@ export function ReactFlowProvider({ width, height, fitView, + minZoom, + maxZoom, + fitViewOptions, nodeOrigin, nodeExtent, }) diff --git a/packages/react/src/container/ReactFlow/Wrapper.tsx b/packages/react/src/container/ReactFlow/Wrapper.tsx index 71a84316..c2940399 100644 --- a/packages/react/src/container/ReactFlow/Wrapper.tsx +++ b/packages/react/src/container/ReactFlow/Wrapper.tsx @@ -2,7 +2,7 @@ import { useContext, type ReactNode } from 'react'; import StoreContext from '../../contexts/StoreContext'; import { ReactFlowProvider } from '../../components/ReactFlowProvider'; -import type { Node, Edge } from '../../types'; +import type { Node, Edge, FitViewOptions } from '../../types'; import { CoordinateExtent, NodeOrigin } from '@xyflow/system'; export function Wrapper({ @@ -14,6 +14,9 @@ export function Wrapper({ width, height, fitView, + fitViewOptions, + minZoom, + maxZoom, nodeOrigin, nodeExtent, }: { @@ -25,6 +28,9 @@ export function Wrapper({ width?: number; height?: number; fitView?: boolean; + fitViewOptions?: FitViewOptions; + minZoom?: number; + maxZoom?: number; nodeOrigin?: NodeOrigin; nodeExtent?: CoordinateExtent; }) { @@ -47,6 +53,9 @@ export function Wrapper({ initialWidth={width} initialHeight={height} fitView={fitView} + fitViewOptions={fitViewOptions} + initialMinZoom={minZoom} + initialMaxZoom={maxZoom} nodeOrigin={nodeOrigin} nodeExtent={nodeExtent} > diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index 31389887..2247a004 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -177,6 +177,9 @@ function ReactFlow( width={width} height={height} fitView={fitView} + fitViewOptions={fitViewOptions} + minZoom={minZoom} + maxZoom={maxZoom} nodeOrigin={nodeOrigin} nodeExtent={nodeExtent} > diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 7682dc90..5588718c 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -18,7 +18,7 @@ import { import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; import getInitialState from './initialState'; -import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams } from '../types'; +import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams, FitViewOptions } from '../types'; const createStore = ({ nodes, @@ -28,6 +28,9 @@ const createStore = ({ width, height, fitView, + fitViewOptions, + minZoom, + maxZoom, nodeOrigin, nodeExtent, }: { @@ -38,6 +41,9 @@ const createStore = ({ width?: number; height?: number; fitView?: boolean; + fitViewOptions?: FitViewOptions; + minZoom?: number; + maxZoom?: number; nodeOrigin?: NodeOrigin; nodeExtent?: CoordinateExtent; }) => @@ -70,7 +76,20 @@ const createStore = ({ } return { - ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), + ...getInitialState({ + nodes, + edges, + width, + height, + fitView, + fitViewOptions, + minZoom, + maxZoom, + nodeOrigin, + nodeExtent, + defaultNodes, + defaultEdges, + }), setNodes: (nodes: Node[]) => { const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get(); /* diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index 996cc148..34507efd 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -12,7 +12,7 @@ import { CoordinateExtent, } from '@xyflow/system'; -import type { Edge, InternalNode, Node, ReactFlowStore } from '../types'; +import type { Edge, FitViewOptions, InternalNode, Node, ReactFlowStore } from '../types'; const getInitialState = ({ nodes, @@ -22,6 +22,9 @@ const getInitialState = ({ width, height, fitView, + fitViewOptions, + minZoom = 0.5, + maxZoom = 2, nodeOrigin, nodeExtent, }: { @@ -32,6 +35,9 @@ const getInitialState = ({ width?: number; height?: number; fitView?: boolean; + fitViewOptions?: FitViewOptions; + minZoom?: number; + maxZoom?: number; nodeOrigin?: NodeOrigin; nodeExtent?: CoordinateExtent; } = {}): ReactFlowStore => { @@ -59,7 +65,14 @@ const getInitialState = ({ filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight)), }); - const { x, y, zoom } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1); + const { x, y, zoom } = getViewportForBounds( + bounds, + width, + height, + minZoom, + maxZoom, + fitViewOptions?.padding ?? 0.1 + ); transform = [x, y, zoom]; } @@ -80,8 +93,8 @@ const getInitialState = ({ hasDefaultNodes: defaultNodes !== undefined, hasDefaultEdges: defaultEdges !== undefined, panZoom: null, - minZoom: 0.5, - maxZoom: 2, + minZoom, + maxZoom, translateExtent: infiniteExtent, nodeExtent: storeNodeExtent, nodesSelectionActive: false, @@ -110,7 +123,7 @@ const getInitialState = ({ multiSelectionActive: false, fitViewQueued: fitView ?? false, - fitViewOptions: undefined, + fitViewOptions, fitViewResolver: null, connection: { ...initialConnection }, From 4236adbc462b3f65ee41869ef426491ed3fa8ba0 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 13:08:05 +0200 Subject: [PATCH 21/40] chore(changeset): add --- .changeset/happy-lobsters-speak.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/happy-lobsters-speak.md diff --git a/.changeset/happy-lobsters-speak.md b/.changeset/happy-lobsters-speak.md new file mode 100644 index 00000000..59b81980 --- /dev/null +++ b/.changeset/happy-lobsters-speak.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': minor +--- + +Add initialMinZoom, initialMaxZoom and initialFitViewOptions to ReactFlowProvider From 9878e93601bf29d2d53ad1e564a49fc00cf4a4c5 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 13:09:19 +0200 Subject: [PATCH 22/40] refactor(provider): rename fitviewoptions to initialfitviewoptions --- packages/react/src/components/ReactFlowProvider/index.tsx | 6 +++--- packages/react/src/container/ReactFlow/Wrapper.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react/src/components/ReactFlowProvider/index.tsx b/packages/react/src/components/ReactFlowProvider/index.tsx index 74f19f81..11a9c6b8 100644 --- a/packages/react/src/components/ReactFlowProvider/index.tsx +++ b/packages/react/src/components/ReactFlowProvider/index.tsx @@ -22,9 +22,9 @@ export type ReactFlowProviderProps = { /** When `true`, the flow will be zoomed and panned to fit all the nodes initially provided. */ fitView?: boolean; /** - * You can provide an object of options to customize the fitView behavior. + * You can provide an object of options to customize the initial fitView behavior. */ - fitViewOptions?: FitViewOptions; + initialFitViewOptions?: FitViewOptions; /** Initial minimum zoom level */ initialMinZoom?: number; /** Initial maximum zoom level */ @@ -93,7 +93,7 @@ export function ReactFlowProvider({ initialHeight: height, initialMinZoom: minZoom, initialMaxZoom: maxZoom, - fitViewOptions, + initialFitViewOptions: fitViewOptions, fitView, nodeOrigin, nodeExtent, diff --git a/packages/react/src/container/ReactFlow/Wrapper.tsx b/packages/react/src/container/ReactFlow/Wrapper.tsx index c2940399..9ae0aa62 100644 --- a/packages/react/src/container/ReactFlow/Wrapper.tsx +++ b/packages/react/src/container/ReactFlow/Wrapper.tsx @@ -53,7 +53,7 @@ export function Wrapper({ initialWidth={width} initialHeight={height} fitView={fitView} - fitViewOptions={fitViewOptions} + initialFitViewOptions={fitViewOptions} initialMinZoom={minZoom} initialMaxZoom={maxZoom} nodeOrigin={nodeOrigin} From 93034b50dc3767607aac31f0db112a7e07a92652 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 16:05:28 +0200 Subject: [PATCH 23/40] chore(react): init check --- packages/system/src/utils/store.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 1546a8ff..d94a7dff 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -125,7 +125,9 @@ export function adoptUserNodes( } if ( - (!internalNode.measured || !internalNode.measured.width || !internalNode.measured.height) && + (internalNode.measured === undefined || + internalNode.measured.width === undefined || + internalNode.measured.height === undefined) && !internalNode.hidden ) { nodesInitialized = false; From 4e681f9c529c3f4f8b2ac5d25b4db7878c197e14 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 15 Apr 2025 16:07:03 +0200 Subject: [PATCH 24/40] chore(changeset): add --- .changeset/red-plums-fly.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/red-plums-fly.md diff --git a/.changeset/red-plums-fly.md b/.changeset/red-plums-fly.md new file mode 100644 index 00000000..f94d9fda --- /dev/null +++ b/.changeset/red-plums-fly.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Allow zero as a valid node width/height value From bee2f4aa057b884d2ace2c134e1871950792767e Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 17 Apr 2025 12:54:47 +0200 Subject: [PATCH 25/40] feat(xy-resizer): add resize direction #2986 --- .../NodeResizer/BottomRightResizer.tsx | 21 +++++++++++++++++++ .../react/src/examples/NodeResizer/index.tsx | 9 ++++++++ .../NodeResizer/NodeResizeControl.tsx | 2 ++ .../NodeResizer/types.ts | 6 ++++++ packages/system/src/xyresizer/XYResizer.ts | 18 +++++++++++++--- packages/system/src/xyresizer/types.ts | 6 ++++++ 6 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 examples/react/src/examples/NodeResizer/BottomRightResizer.tsx diff --git a/examples/react/src/examples/NodeResizer/BottomRightResizer.tsx b/examples/react/src/examples/NodeResizer/BottomRightResizer.tsx new file mode 100644 index 00000000..ca860fdf --- /dev/null +++ b/examples/react/src/examples/NodeResizer/BottomRightResizer.tsx @@ -0,0 +1,21 @@ +import { memo, FC } from 'react'; +import { Handle, Position, NodeProps, NodeResizeControl, ResizeControlVariant } from '@xyflow/react'; + +const CustomResizerNode: FC = ({ data }) => { + return ( + <> + + +
{data.label}
+ + + ); +}; + +export default memo(CustomResizerNode); diff --git a/examples/react/src/examples/NodeResizer/index.tsx b/examples/react/src/examples/NodeResizer/index.tsx index 397c1f22..ce6faf3b 100644 --- a/examples/react/src/examples/NodeResizer/index.tsx +++ b/examples/react/src/examples/NodeResizer/index.tsx @@ -15,12 +15,14 @@ import DefaultResizer from './DefaultResizer'; import CustomResizer from './CustomResizer'; import VerticalResizer from './VerticalResizer'; import HorizontalResizer from './HorizontalResizer'; +import BottomRightResizer from './BottomRightResizer'; const nodeTypes = { defaultResizer: DefaultResizer, customResizer: CustomResizer, verticalResizer: VerticalResizer, horizontalResizer: HorizontalResizer, + bottomRightResizer: BottomRightResizer, }; const nodeStyle = { @@ -166,6 +168,13 @@ const initialNodes: Node[] = [ expandParent: true, style: { ...nodeStyle }, }, + { + id: '6', + type: 'bottomRightResizer', + data: { label: 'Bottom Right with horizontal direction' }, + position: { x: 500, y: 500 }, + style: { ...nodeStyle }, + }, ]; const CustomNodeFlow = () => { diff --git a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx index 0748ffa6..1b6393c6 100644 --- a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx +++ b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx @@ -32,6 +32,7 @@ function ResizeControl({ maxWidth = Number.MAX_VALUE, maxHeight = Number.MAX_VALUE, keepAspectRatio = false, + resizeDirection, shouldResize, onResizeStart, onResize, @@ -166,6 +167,7 @@ function ResizeControl({ maxHeight, }, keepAspectRatio, + resizeDirection, onResizeStart, onResize, onResizeEnd, diff --git a/packages/react/src/additional-components/NodeResizer/types.ts b/packages/react/src/additional-components/NodeResizer/types.ts index e34329b1..6ca29494 100644 --- a/packages/react/src/additional-components/NodeResizer/types.ts +++ b/packages/react/src/additional-components/NodeResizer/types.ts @@ -3,6 +3,7 @@ import type { ControlPosition, ControlLinePosition, ResizeControlVariant, + ResizeControlDirection, ShouldResize, OnResizeStart, OnResize, @@ -97,6 +98,11 @@ export type ResizeControlProps = Pick< * @example ResizeControlVariant.Handle, ResizeControlVariant.Line */ variant?: ResizeControlVariant; + /** + * The direction the user can resize the node. + * If not provided, the user can resize in any direction. + */ + resizeDirection?: ResizeControlDirection; className?: string; style?: CSSProperties; children?: ReactNode; diff --git a/packages/system/src/xyresizer/XYResizer.ts b/packages/system/src/xyresizer/XYResizer.ts index f4cd150b..03a0675e 100644 --- a/packages/system/src/xyresizer/XYResizer.ts +++ b/packages/system/src/xyresizer/XYResizer.ts @@ -12,7 +12,15 @@ import type { Transform, XYPosition, } from '../types'; -import type { OnResize, OnResizeEnd, OnResizeStart, ResizeDragEvent, ShouldResize, ControlPosition } from './types'; +import type { + OnResize, + OnResizeEnd, + OnResizeStart, + ResizeDragEvent, + ShouldResize, + ControlPosition, + ResizeControlDirection, +} from './types'; const initPrevValues = { width: 0, height: 0, x: 0, y: 0 }; @@ -60,6 +68,7 @@ type XYResizerUpdateParams = { maxHeight: number; }; keepAspectRatio: boolean; + resizeDirection?: ResizeControlDirection; onResizeStart: OnResizeStart | undefined; onResize: OnResize | undefined; onResizeEnd: OnResizeEnd | undefined; @@ -99,6 +108,7 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X controlPosition, boundaries, keepAspectRatio, + resizeDirection, onResizeStart, onResize, onResizeEnd, @@ -251,8 +261,10 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X } if (isWidthChange || isHeightChange) { - change.width = isWidthChange ? width : prevValues.width; - change.height = isHeightChange ? height : prevValues.height; + change.width = + isWidthChange && (!resizeDirection || resizeDirection === 'horizontal') ? width : prevValues.width; + change.height = + isHeightChange && (!resizeDirection || resizeDirection === 'vertical') ? height : prevValues.height; prevValues.width = change.width; prevValues.height = change.height; } diff --git a/packages/system/src/xyresizer/types.ts b/packages/system/src/xyresizer/types.ts index 34cad9e8..1d16eb3a 100644 --- a/packages/system/src/xyresizer/types.ts +++ b/packages/system/src/xyresizer/types.ts @@ -35,6 +35,12 @@ export enum ResizeControlVariant { Handle = 'handle', } +/** + * The direction the user can resize the node. + * @public + */ +export type ResizeControlDirection = 'horizontal' | 'vertical'; + export const XY_RESIZER_HANDLE_POSITIONS: ControlPosition[] = ['top-left', 'top-right', 'bottom-left', 'bottom-right']; export const XY_RESIZER_LINE_POSITIONS: ControlLinePosition[] = ['top', 'right', 'bottom', 'left']; From cda61ff243e8300350bd83514a50e0f1b5e401bb Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 17 Apr 2025 13:00:17 +0200 Subject: [PATCH 26/40] chore(ResizeControlLine): cleanup type --- packages/react/src/additional-components/NodeResizer/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/additional-components/NodeResizer/types.ts b/packages/react/src/additional-components/NodeResizer/types.ts index 6ca29494..e6dd9d36 100644 --- a/packages/react/src/additional-components/NodeResizer/types.ts +++ b/packages/react/src/additional-components/NodeResizer/types.ts @@ -111,6 +111,6 @@ export type ResizeControlProps = Pick< /** * @expand */ -export type ResizeControlLineProps = ResizeControlProps & { +export type ResizeControlLineProps = Omit & { position?: ControlLinePosition; }; From a7d10ffce5a0195471681980f97b1b5f6c448f35 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 17 Apr 2025 13:01:48 +0200 Subject: [PATCH 27/40] chore(changeset): add --- .changeset/brave-cherries-hunt.md | 5 +++++ .changeset/two-pugs-drive.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/brave-cherries-hunt.md create mode 100644 .changeset/two-pugs-drive.md diff --git a/.changeset/brave-cherries-hunt.md b/.changeset/brave-cherries-hunt.md new file mode 100644 index 00000000..952ac029 --- /dev/null +++ b/.changeset/brave-cherries-hunt.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +add resizeDirection for XYResizer diff --git a/.changeset/two-pugs-drive.md b/.changeset/two-pugs-drive.md new file mode 100644 index 00000000..480c18f0 --- /dev/null +++ b/.changeset/two-pugs-drive.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Add resizeDirection prop for the NodeResizeControl component From 02a3916d47ea5afca30972d428f5935dc067bb4d Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Thu, 17 Apr 2025 13:04:19 +0200 Subject: [PATCH 28/40] chore(changeset): update --- .changeset/two-pugs-drive.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/two-pugs-drive.md b/.changeset/two-pugs-drive.md index 480c18f0..6d58d227 100644 --- a/.changeset/two-pugs-drive.md +++ b/.changeset/two-pugs-drive.md @@ -1,5 +1,5 @@ --- -'@xyflow/react': patch +'@xyflow/react': minor --- -Add resizeDirection prop for the NodeResizeControl component +Add `resizeDirection` prop for the `NodeResizeControl` component From cb6f0736dda6ef775b2129c2ff5e9f751a5886fd Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 17 Apr 2025 13:22:56 +0200 Subject: [PATCH 29/40] refactor(changes): allow set attributes to be width or height --- .../NodeResizer/NodeResizeControl.tsx | 3 ++- packages/react/src/utils/changes.ts | 8 ++++++-- packages/system/src/types/changes.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx index 1b6393c6..beaeb527 100644 --- a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx +++ b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx @@ -118,11 +118,12 @@ function ResizeControl({ } if (change.width !== undefined && change.height !== undefined) { + const setAttributes = !resizeDirection ? true : resizeDirection === 'horizontal' ? 'width' : 'height'; const dimensionChange: NodeDimensionChange = { id, type: 'dimensions', resizing: true, - setAttributes: true, + setAttributes, dimensions: { width: change.width, height: change.height, diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index f1494bf4..f2d9bdd3 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -130,8 +130,12 @@ function applyChange(change: any, element: any): any { element.measured.height = change.dimensions.height; if (change.setAttributes) { - element.width = change.dimensions.width; - element.height = change.dimensions.height; + if (change.setAttributes === true || change.setAttributes === 'width') { + element.width = change.dimensions.width; + } + if (change.setAttributes === true || change.setAttributes === 'height') { + element.height = change.dimensions.height; + } } } diff --git a/packages/system/src/types/changes.ts b/packages/system/src/types/changes.ts index 8ab81a37..999f2cf2 100644 --- a/packages/system/src/types/changes.ts +++ b/packages/system/src/types/changes.ts @@ -7,7 +7,7 @@ export type NodeDimensionChange = { /* if this is true, the node is currently being resized via the NodeResizer */ resizing?: boolean; /* if this is true, we will set width and height of the node and not just the measured dimensions */ - setAttributes?: boolean; + setAttributes?: boolean | 'width' | 'height'; }; export type NodePositionChange = { From 213c0043f36de0880b8fecdcaf403d8758b93f24 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 17 Apr 2025 15:12:17 +0000 Subject: [PATCH 30/40] chore(packages): bump --- .changeset/brave-cherries-hunt.md | 5 ----- .changeset/flat-crabs-attack.md | 5 ----- .changeset/happy-lobsters-speak.md | 5 ----- .changeset/red-plums-fly.md | 5 ----- .changeset/two-pugs-drive.md | 5 ----- packages/react/CHANGELOG.md | 15 +++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 7 +++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 8 ++++++++ packages/system/package.json | 2 +- 11 files changed, 33 insertions(+), 28 deletions(-) delete mode 100644 .changeset/brave-cherries-hunt.md delete mode 100644 .changeset/flat-crabs-attack.md delete mode 100644 .changeset/happy-lobsters-speak.md delete mode 100644 .changeset/red-plums-fly.md delete mode 100644 .changeset/two-pugs-drive.md diff --git a/.changeset/brave-cherries-hunt.md b/.changeset/brave-cherries-hunt.md deleted file mode 100644 index 952ac029..00000000 --- a/.changeset/brave-cherries-hunt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -add resizeDirection for XYResizer diff --git a/.changeset/flat-crabs-attack.md b/.changeset/flat-crabs-attack.md deleted file mode 100644 index 2d23f9cb..00000000 --- a/.changeset/flat-crabs-attack.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Keep node seleciton on pane click if elementsSelectable=false diff --git a/.changeset/happy-lobsters-speak.md b/.changeset/happy-lobsters-speak.md deleted file mode 100644 index 59b81980..00000000 --- a/.changeset/happy-lobsters-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': minor ---- - -Add initialMinZoom, initialMaxZoom and initialFitViewOptions to ReactFlowProvider diff --git a/.changeset/red-plums-fly.md b/.changeset/red-plums-fly.md deleted file mode 100644 index f94d9fda..00000000 --- a/.changeset/red-plums-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Allow zero as a valid node width/height value diff --git a/.changeset/two-pugs-drive.md b/.changeset/two-pugs-drive.md deleted file mode 100644 index 6d58d227..00000000 --- a/.changeset/two-pugs-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': minor ---- - -Add `resizeDirection` prop for the `NodeResizeControl` component diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index a90a6d01..b7d0ded6 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,20 @@ # @xyflow/react +## 12.6.0 + +### Minor Changes + +- [#5219](https://github.com/xyflow/xyflow/pull/5219) [`4236adbc`](https://github.com/xyflow/xyflow/commit/4236adbc462b3f65ee41869ef426491ed3fa8ba0) Thanks [@moklick](https://github.com/moklick)! - Add initialMinZoom, initialMaxZoom and initialFitViewOptions to ReactFlowProvider + +- [#5227](https://github.com/xyflow/xyflow/pull/5227) [`a7d10ffc`](https://github.com/xyflow/xyflow/commit/a7d10ffce5a0195471681980f97b1b5f6c448f35) Thanks [@moklick](https://github.com/moklick)! - Add `resizeDirection` prop for the `NodeResizeControl` component + +### Patch Changes + +- [#5217](https://github.com/xyflow/xyflow/pull/5217) [`bce74e88`](https://github.com/xyflow/xyflow/commit/bce74e8811a98c967b5bd06c3e5aecde24c8b679) Thanks [@moklick](https://github.com/moklick)! - Keep node seleciton on pane click if elementsSelectable=false + +- Updated dependencies [[`a7d10ffc`](https://github.com/xyflow/xyflow/commit/a7d10ffce5a0195471681980f97b1b5f6c448f35), [`4e681f9c`](https://github.com/xyflow/xyflow/commit/4e681f9c529c3f4f8b2ac5d25b4db7878c197e14)]: + - @xyflow/system@0.0.57 + ## 12.5.6 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index ffae487a..aa21a419 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.6", + "version": "12.6.0", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 5f83ddc0..43cfc190 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,12 @@ # @xyflow/svelte +## 0.1.37 + +### Patch Changes + +- Updated dependencies [[`a7d10ffc`](https://github.com/xyflow/xyflow/commit/a7d10ffce5a0195471681980f97b1b5f6c448f35), [`4e681f9c`](https://github.com/xyflow/xyflow/commit/4e681f9c529c3f4f8b2ac5d25b4db7878c197e14)]: + - @xyflow/system@0.0.57 + ## 0.1.36 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 2085642e..1c0f4bc0 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.36", + "version": "0.1.37", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "keywords": [ "svelte", diff --git a/packages/system/CHANGELOG.md b/packages/system/CHANGELOG.md index 8c2eb8be..67fd825b 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,13 @@ # @xyflow/system +## 0.0.57 + +### Patch Changes + +- [#5227](https://github.com/xyflow/xyflow/pull/5227) [`a7d10ffc`](https://github.com/xyflow/xyflow/commit/a7d10ffce5a0195471681980f97b1b5f6c448f35) Thanks [@moklick](https://github.com/moklick)! - add resizeDirection for XYResizer + +- [#5221](https://github.com/xyflow/xyflow/pull/5221) [`4e681f9c`](https://github.com/xyflow/xyflow/commit/4e681f9c529c3f4f8b2ac5d25b4db7878c197e14) Thanks [@moklick](https://github.com/moklick)! - Allow zero as a valid node width/height value + ## 0.0.56 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index e957db8f..7acbc78c 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.56", + "version": "0.0.57", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From 2effb90b1c593097d5e137aaf8be2c163cefe086 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 6 May 2025 23:30:49 +0200 Subject: [PATCH 31/40] chore(react): cleanup tsdoc annotations for ReactFlow --- packages/react/src/types/component-props.ts | 33 ++------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index 63f0a1be..e1bf01e1 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -85,22 +85,11 @@ export interface ReactFlowProps; @@ -148,7 +136,6 @@ export interface ReactFlowProps void; /** @@ -209,7 +196,6 @@ export interface ReactFlowProps void; /** * When a connection line is completed and two nodes are connected by the user, this event fires with the new connection. - * * You can use the `addEdge` utility to convert the connection to a complete edge. * @example // Use helper function to update edges onConnect * import ReactFlow, { addEdge } from '@xyflow/react'; @@ -277,9 +263,7 @@ export interface ReactFlowProps; /** * Custom node types to be available in a flow. - * * React Flow matches a node's type to a component in the `nodeTypes` object. - * @TODO check if @default is correct * @default { * input: InputNode, * default: DefaultNode, @@ -294,9 +278,7 @@ export interface ReactFlowProps void; /** * By default, the viewport extends infinitely. You can use this prop to set a boundary. - * * The first pair of coordinates is the top left boundary and the second pair is the bottom right. * @default [[-∞, -∞], [+∞, +∞]] * @example [[-1000, -10000], [1000, 1000]] @@ -502,7 +481,6 @@ export interface ReactFlowProps; /** * With a threshold greater than zero you can delay node drag events. - * * If threshold equals 1, you need to drag the node 1 pixel before a drag event is fired. - * - * 1 is the default value, so clicks don't trigger drag events. + * 1 is the default value, so that clicks don't trigger drag events. * @default 1 */ nodeDragThreshold?: number; From 67e1cb6891078dbcb9e1d06b9f9fdbfc79860ab6 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 6 May 2025 23:31:28 +0200 Subject: [PATCH 32/40] chore(changeset): add --- .changeset/hot-phones-knock.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/hot-phones-knock.md diff --git a/.changeset/hot-phones-knock.md b/.changeset/hot-phones-knock.md new file mode 100644 index 00000000..d041b486 --- /dev/null +++ b/.changeset/hot-phones-knock.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Cleanup TSDoc annotations for ReactFlow From b764875dec528f84117c6e274f3e41b131c82273 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 7 May 2025 09:39:30 +0200 Subject: [PATCH 33/40] fix(react): call onNodesChange for uncontrolled flows that use updateNode #5062 --- examples/react/src/examples/Basic/index.tsx | 9 +++-- .../src/components/BatchProvider/index.tsx | 38 +++++++++---------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/examples/react/src/examples/Basic/index.tsx b/examples/react/src/examples/Basic/index.tsx index 5754fd62..168bcff6 100644 --- a/examples/react/src/examples/Basic/index.tsx +++ b/examples/react/src/examples/Basic/index.tsx @@ -11,6 +11,7 @@ import { useReactFlow, Panel, OnNodeDrag, + FitViewOptions, } from '@xyflow/react'; const onNodeDrag: OnNodeDrag = (_, node: Node, nodes: Node[]) => console.log('drag', node, nodes); @@ -54,6 +55,9 @@ const initialEdges: Edge[] = [ ]; const defaultEdgeOptions = {}; +const fitViewOptions: FitViewOptions = { + padding: { top: '100px', left: '0%', right: '10%', bottom: 0.1 }, +}; const BasicFlow = () => { const { @@ -135,6 +139,7 @@ const BasicFlow = () => { { minZoom={0.2} maxZoom={4} fitView - fitViewOptions={{ - padding: { top: '100px', left: '0%', right: '10%', bottom: 0.1 }, - }} + fitViewOptions={fitViewOptions} defaultEdgeOptions={defaultEdgeOptions} selectNodesOnDrag={false} elevateEdgesOnSelect diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index f41b79a8..92bb4370 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -40,28 +40,28 @@ export function BatchProvider[]; + if (hasDefaultNodes) { setNodes(next); - } else { - // When a controlled flow is used we need to collect the changes - const changes = getElementsDiffChanges({ - items: next, - lookup: nodeLookup, - }) as NodeChange[]; + } - // We only want to fire onNodesChange if there are changes to the nodes - if (changes.length > 0) { - onNodesChange?.(changes); - } else if (fitViewQueued) { - // If there are no changes to the nodes, we still need to call setNodes - // to trigger a re-render and fitView. - window.requestAnimationFrame(() => { - const { fitViewQueued, nodes, setNodes } = store.getState(); - if (fitViewQueued) { - setNodes(nodes); - } - }); - } + // We only want to fire onNodesChange if there are changes to the nodes + if (changes.length > 0) { + onNodesChange?.(changes); + } else if (fitViewQueued) { + // If there are no changes to the nodes, we still need to call setNodes + // to trigger a re-render and fitView. + window.requestAnimationFrame(() => { + const { fitViewQueued, nodes, setNodes } = store.getState(); + if (fitViewQueued) { + setNodes(nodes); + } + }); } }, []); From 895b5d81c8ee5236009820ecd0ed6806c6e59e29 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 7 May 2025 09:40:26 +0200 Subject: [PATCH 34/40] chore(changeset): add --- .changeset/eight-buses-admire.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eight-buses-admire.md diff --git a/.changeset/eight-buses-admire.md b/.changeset/eight-buses-admire.md new file mode 100644 index 00000000..b678a287 --- /dev/null +++ b/.changeset/eight-buses-admire.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Call `onNodesChange` for uncontrolled flows that use `updateNode` From 9684204344507e73b90c90aa7082fdd4e5a5ac0a Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 7 May 2025 09:41:44 +0200 Subject: [PATCH 35/40] chore(batchprovider): cleanup --- packages/react/src/components/BatchProvider/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 92bb4370..b2ed270f 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -40,7 +40,6 @@ export function BatchProvider Date: Mon, 12 May 2025 09:55:41 +0200 Subject: [PATCH 36/40] fix(panel-position): do not use margin for gaps #4431 --- packages/system/src/styles/init.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/system/src/styles/init.css b/packages/system/src/styles/init.css index ca4d6de7..ad364dba 100644 --- a/packages/system/src/styles/init.css +++ b/packages/system/src/styles/init.css @@ -268,14 +268,13 @@ svg.xy-flow__connectionline { .xy-flow__panel { position: absolute; z-index: 5; - margin: 15px; &.top { - top: 0; + top: 15px; } &.bottom { - bottom: 0; + bottom: 15px; } &.top, @@ -287,11 +286,11 @@ svg.xy-flow__connectionline { } &.left { - left: 0; + left: 15px; } &.right { - right: 0; + right: 15px; } &.left, From 2a03213b0695d504f831579ec9df3f9de2d3e0bd Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 12 May 2025 09:56:23 +0200 Subject: [PATCH 37/40] chore(changeset): add --- .changeset/itchy-pumas-share.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/itchy-pumas-share.md diff --git a/.changeset/itchy-pumas-share.md b/.changeset/itchy-pumas-share.md new file mode 100644 index 00000000..09c4dc6e --- /dev/null +++ b/.changeset/itchy-pumas-share.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Center panel correctly when bottom-center or top-center position is used From ee509176cb1a6766d20700c0d822554accc755ac Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 12 May 2025 11:59:58 +0200 Subject: [PATCH 38/40] chore(panel): less intrusive fix --- packages/system/src/styles/init.css | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/system/src/styles/init.css b/packages/system/src/styles/init.css index ad364dba..5f082ff8 100644 --- a/packages/system/src/styles/init.css +++ b/packages/system/src/styles/init.css @@ -268,36 +268,37 @@ svg.xy-flow__connectionline { .xy-flow__panel { position: absolute; z-index: 5; + margin: 15px; &.top { - top: 15px; + top: 0; } &.bottom { - bottom: 15px; + bottom: 0; } &.top, &.bottom { &.center { left: 50%; - transform: translateX(-50%); + transform: translateX(-15px) translateX(-50%); } } &.left { - left: 15px; + left: 0; } &.right { - right: 15px; + right: 0; } &.left, &.right { &.center { top: 50%; - transform: translateY(-50%); + transform: translateY(-15px) translateY(-50%); } } } From 2df553e61154c1d6ebcb1bfc86f021472df2bae9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 12 May 2025 10:06:30 +0000 Subject: [PATCH 39/40] chore(packages): bump --- .changeset/eight-buses-admire.md | 5 ----- .changeset/hot-phones-knock.md | 5 ----- .changeset/itchy-pumas-share.md | 5 ----- packages/react/CHANGELOG.md | 11 +++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 7 +++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 6 ++++++ packages/system/package.json | 2 +- 9 files changed, 27 insertions(+), 18 deletions(-) delete mode 100644 .changeset/eight-buses-admire.md delete mode 100644 .changeset/hot-phones-knock.md delete mode 100644 .changeset/itchy-pumas-share.md diff --git a/.changeset/eight-buses-admire.md b/.changeset/eight-buses-admire.md deleted file mode 100644 index b678a287..00000000 --- a/.changeset/eight-buses-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Call `onNodesChange` for uncontrolled flows that use `updateNode` diff --git a/.changeset/hot-phones-knock.md b/.changeset/hot-phones-knock.md deleted file mode 100644 index d041b486..00000000 --- a/.changeset/hot-phones-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Cleanup TSDoc annotations for ReactFlow diff --git a/.changeset/itchy-pumas-share.md b/.changeset/itchy-pumas-share.md deleted file mode 100644 index 09c4dc6e..00000000 --- a/.changeset/itchy-pumas-share.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Center panel correctly when bottom-center or top-center position is used diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index b7d0ded6..495cfd7c 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,16 @@ # @xyflow/react +## 12.6.1 + +### Patch Changes + +- [#5249](https://github.com/xyflow/xyflow/pull/5249) [`895b5d81`](https://github.com/xyflow/xyflow/commit/895b5d81c8ee5236009820ecd0ed6806c6e59e29) Thanks [@moklick](https://github.com/moklick)! - Call `onNodesChange` for uncontrolled flows that use `updateNode` + +- [#5247](https://github.com/xyflow/xyflow/pull/5247) [`67e1cb68`](https://github.com/xyflow/xyflow/commit/67e1cb6891078dbcb9e1d06b9f9fdbfc79860ab6) Thanks [@moklick](https://github.com/moklick)! - Cleanup TSDoc annotations for ReactFlow + +- Updated dependencies [[`2a03213b`](https://github.com/xyflow/xyflow/commit/2a03213b0695d504f831579ec9df3f9de2d3e0bd)]: + - @xyflow/system@0.0.58 + ## 12.6.0 ### Minor Changes diff --git a/packages/react/package.json b/packages/react/package.json index aa21a419..c85ed8ed 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.6.0", + "version": "12.6.1", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 43cfc190..6b5c3b22 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,12 @@ # @xyflow/svelte +## 0.1.38 + +### Patch Changes + +- Updated dependencies [[`2a03213b`](https://github.com/xyflow/xyflow/commit/2a03213b0695d504f831579ec9df3f9de2d3e0bd)]: + - @xyflow/system@0.0.58 + ## 0.1.37 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 1c0f4bc0..c29caebd 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.37", + "version": "0.1.38", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "keywords": [ "svelte", diff --git a/packages/system/CHANGELOG.md b/packages/system/CHANGELOG.md index 67fd825b..d8ce85fe 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,11 @@ # @xyflow/system +## 0.0.58 + +### Patch Changes + +- [#5252](https://github.com/xyflow/xyflow/pull/5252) [`2a03213b`](https://github.com/xyflow/xyflow/commit/2a03213b0695d504f831579ec9df3f9de2d3e0bd) Thanks [@moklick](https://github.com/moklick)! - Center panel correctly when bottom-center or top-center position is used + ## 0.0.57 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index 7acbc78c..998f2f46 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.57", + "version": "0.0.58", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From a95f0e2fbfc2d070d9bd70b753d1606a87332e3f Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 14 May 2025 11:11:34 +0200 Subject: [PATCH 40/40] added onReconnect type --- .changeset/rotten-bikes-hunt.md | 5 +++++ packages/system/src/types/general.ts | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 .changeset/rotten-bikes-hunt.md diff --git a/.changeset/rotten-bikes-hunt.md b/.changeset/rotten-bikes-hunt.md new file mode 100644 index 00000000..e4dd48ad --- /dev/null +++ b/.changeset/rotten-bikes-hunt.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Added OnReconnect types diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index a2fba7dd..3444fdaf 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -80,6 +80,19 @@ export type OnConnectStart = (event: MouseEvent | TouchEvent, params: OnConnectS export type OnConnect = (connection: Connection) => void; export type OnConnectEnd = (event: MouseEvent | TouchEvent, connectionState: FinalConnectionState) => void; +export type OnReconnect = (oldEdge: EdgeType, newConnection: Connection) => void; +export type OnRecoonnectStart = ( + event: MouseEvent | TouchEvent, + edge: EdgeType, + handleType: HandleType +) => void; +export type OnReconnectEnd = ( + event: MouseEvent | TouchEvent, + edge: EdgeType, + handleType: HandleType, + connectionState: FinalConnectionState +) => void; + export type IsValidConnection = (edge: EdgeBase | Connection) => boolean; /**