diff --git a/README.md b/README.md index 722fa001..df474f4f 100644 --- a/README.md +++ b/README.md @@ -17,20 +17,20 @@ Powerful open source libraries for building node-based UIs with React or Svelte. ## The xyflow mono repo The xyflow repository is the home of four packages: -* React Flow v11 `reactflow` [v11 branch](https://github.com/xyflow/xyflow/tree/v11) -* React Flow v12 (not published yet) [packages/react](./packages/react) +* React Flow 11 `reactflow` [v11 branch](https://github.com/xyflow/xyflow/tree/v11) +* React Flow 12 (beta) `@xyflow/svelte` [packages/react](./packages/react) * Svelte Flow `@xyflow/svelte` [packages/svelte](./packages/svelte) * Shared helper library `@xyflow/system` [packages/system](./packages/system) **We just moved repositories** from the @wbkd org to this one. React Flow v11 will remain on the [v11 branch](https://github.com/xyflow/xyflow/tree/v11). When we have a stable v12, the package name of React Flow will change from `reactflow` to `@xyflow/react`. -## Commercial Usage +## Commercial usage **Are you using React Flow or Svelte Flow for a personal project?** Great! No sponsorship needed, you can support us by reporting any bugs you find, sending us screenshots of your projects, and starring us on Github 🌟 **Are you using React Flow or Svelte Flow at your organization and making money from it?** Awesome! We rely on your support to keep our libraries developed and maintained under an MIT License, just how we like it. For React Flow you can do that on the [React Flow Pro website](https://reactflow.dev/pro) and for both of our libraries you can do it through [Github Sponsors](https://github.com/sponsors/xyflow). -## Getting Started +## Getting started The best way to get started is to check out the [React Flow](https://reactflow.dev/learn) or [Svelte Flow](https://svelteflow.dev/learn) learn section. However if you want to get a sneak peek of how to install the and use the libraries you can see it here: diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 0bc7f603..04efec3a 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,12 @@ # @xyflow/react +## 12.0.0-next.12 + +## Patch changes + +- fix useNodesData: handle invalid node id thanks @saswatax +- fix forwardRef: use custom fixForwardRef function + ## 12.0.0-next.11 ## Patch changes diff --git a/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx b/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx index c84c2d3b..6061d8a7 100644 --- a/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx +++ b/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx @@ -96,6 +96,7 @@ export function EdgeUpdateAnchors({ onEdgeUpdateEnd: _onEdgeUpdateEnd, updateConnection, getTransform: () => store.getState().transform, + getConnectionStartHandle: () => store.getState().connectionStartHandle, }); }; diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index f1f84cce..ee36d066 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -4,7 +4,6 @@ import { type TouchEvent as ReactTouchEvent, type ForwardedRef, memo, - forwardRef, } from 'react'; import cc from 'classcat'; import { shallow } from 'zustand/shallow'; @@ -24,6 +23,7 @@ import { import { useStore, useStoreApi } from '../../hooks/useStore'; import { useNodeId } from '../../contexts/NodeIdContext'; import { type ReactFlowState } from '../../types'; +import { fixedForwardRef } from '../../utils'; export interface HandleComponentProps extends HandleProps, Omit, 'id'> {} @@ -140,6 +140,7 @@ function HandleComponent( onConnect: onConnectExtended, isValidConnection: isValidConnection || currentStore.isValidConnection, getTransform: () => store.getState().transform, + getConnectionStartHandle: () => store.getState().connectionStartHandle, }); } @@ -242,4 +243,4 @@ function HandleComponent( /** * The Handle component is a UI element that is used to connect nodes. */ -export const Handle = memo(forwardRef(HandleComponent)); +export const Handle = memo(fixedForwardRef(HandleComponent)); diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index eb741684..eb6e3a1d 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, forwardRef, type CSSProperties } from 'react'; +import { ForwardedRef, type CSSProperties } from 'react'; import cc from 'classcat'; import { ConnectionLineType, PanOnScrollMode, SelectionMode, infiniteExtent, isMacOs } from '@xyflow/system'; @@ -11,6 +11,7 @@ import { GraphView } from '../GraphView'; import { Wrapper } from './Wrapper'; import type { Edge, Node, ReactFlowProps } from '../../types'; import { defaultViewport as initViewport, defaultNodeOrigin } from './init-values'; +import { fixedForwardRef } from '../../utils/general'; const wrapperStyle: CSSProperties = { width: '100%', @@ -286,4 +287,4 @@ function ReactFlow( ); } -export default forwardRef(ReactFlow); +export default fixedForwardRef(ReactFlow); diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 6f723237..302ffeee 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -16,14 +16,6 @@ import { import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps, NodeProps } from '.'; -// this is needed, to use generics + forwardRef -declare module 'react' { - // eslint-disable-next-line @typescript-eslint/ban-types - function forwardRef( - render: (props: P, ref: React.Ref) => React.ReactElement | null - ): (props: P & React.RefAttributes) => React.ReactElement | null; -} - export type OnNodesChange = (changes: NodeChange[]) => void; export type OnEdgesChange = (changes: EdgeChange[]) => void; diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index 2c2387fc..c9e3ae17 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -1,6 +1,7 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '../types'; +import React from 'react'; /** * Test whether an object is useable as a Node @@ -21,3 +22,11 @@ export const isNode = (element: unknown): element */ export const isEdge = (element: unknown): element is EdgeType => isEdgeBase(element); + +// eslint-disable-next-line @typescript-eslint/ban-types +export function fixedForwardRef( + render: (props: P, ref: React.Ref) => React.ReactNode +): (props: P & React.RefAttributes) => React.ReactNode { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return React.forwardRef(render) as any; +} diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index f784ff70..469b397a 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,17 @@ # @xyflow/svelte +## 0.0.39 + +## ⚠️ Breaking changes + +- `on:nodedragstart`, `on:nodedrag` and `on:nodedragstop` are also getting fired if a selection bix is being dragged. We renamed the `node` param to `targetNode` and set it to `null` if a selection is being dragged. + + +## Patch changes + +- export `EdgeLabel` component +- add "connectionindicator" class for `Handle` component + ## 0.0.38 ## ⚠️ Breaking changes diff --git a/packages/svelte/src/lib/components/Handle/Handle.svelte b/packages/svelte/src/lib/components/Handle/Handle.svelte index e35804fc..5217686c 100644 --- a/packages/svelte/src/lib/components/Handle/Handle.svelte +++ b/packages/svelte/src/lib/components/Handle/Handle.svelte @@ -8,7 +8,8 @@ isMouseEvent, type HandleConnection, areConnectionMapsEqual, - handleConnectionChange + handleConnectionChange, + ConnectionMode } from '@xyflow/system'; import { useStore } from '$lib/store'; @@ -23,6 +24,7 @@ export let isConnectable: $$Props['isConnectable'] = undefined; export let onconnect: $$Props['onconnect'] = undefined; export let ondisconnect: $$Props['ondisconnect'] = undefined; + // @todo implement connectablestart, connectableend // export let isConnectableStart: $$Props['isConnectableStart'] = undefined; // export let isConnectableEnd: $$Props['isConnectableEnd'] = undefined; @@ -32,7 +34,7 @@ const isTarget = type === 'target'; const nodeId = getContext('svelteflow__node_id'); const connectable = getContext>('svelteflow__node_connectable'); - $: handleConnectable = isConnectable !== undefined ? isConnectable : $connectable; + $: isConnectable = isConnectable !== undefined ? isConnectable : $connectable; const handleId = id || null; @@ -99,7 +101,8 @@ onConnectEnd: (event) => { $onConnectEndAction?.(event); }, - getTransform: () => [$viewport.x, $viewport.y, $viewport.zoom] + getTransform: () => [$viewport.x, $viewport.y, $viewport.zoom], + getConnectionStartHandle: () => $connection.startHandle }); } } @@ -124,6 +127,7 @@ prevConnections = connections ?? new Map(); } + $: connectionInProcess = !!$connection.startHandle; $: connectingFrom = $connection.startHandle?.nodeId === nodeId && $connection.startHandle?.type === type && @@ -132,9 +136,12 @@ $connection.endHandle?.nodeId === nodeId && $connection.endHandle?.type === type && $connection.endHandle?.handleId === handleId; + $: isPossibleEndHandle = + $connectionMode === ConnectionMode.Strict + ? $connection.startHandle?.type !== type + : nodeId !== $connection.startHandle?.nodeId || + handleId !== $connection.startHandle?.handleId; $: valid = connectingTo && $connection.status === 'valid'; - - // @todo implement connectablestart, connectableend