From cde899c5be9715c4ff2cc331ea93821102604c62 Mon Sep 17 00:00:00 2001 From: Solomon Astley Date: Sun, 15 Dec 2024 11:45:04 -0800 Subject: [PATCH 001/157] pass through NodeType to connectionLineComponent ReactFlow prop --- .changeset/happy-hats-lay.md | 5 +++++ .../src/components/ConnectionLine/index.tsx | 16 ++++++++-------- packages/react/src/types/component-props.ts | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .changeset/happy-hats-lay.md diff --git a/.changeset/happy-hats-lay.md b/.changeset/happy-hats-lay.md new file mode 100644 index 00000000..3a312bc3 --- /dev/null +++ b/.changeset/happy-hats-lay.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': minor +--- + +Pass `NodeType` type argument from `ReactFlowProps` to `connectionLineComponent` property. diff --git a/packages/react/src/components/ConnectionLine/index.tsx b/packages/react/src/components/ConnectionLine/index.tsx index a5f7e1e2..86479900 100644 --- a/packages/react/src/components/ConnectionLine/index.tsx +++ b/packages/react/src/components/ConnectionLine/index.tsx @@ -11,12 +11,12 @@ import { import { useStore } from '../../hooks/useStore'; import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; -import type { ConnectionLineComponent, ReactFlowState } from '../../types'; +import type { ConnectionLineComponent, Node, ReactFlowState } from '../../types'; import { useConnection } from '../../hooks/useConnection'; -type ConnectionLineWrapperProps = { +type ConnectionLineWrapperProps = { type: ConnectionLineType; - component?: ConnectionLineComponent; + component?: ConnectionLineComponent; containerStyle?: CSSProperties; style?: CSSProperties; }; @@ -29,7 +29,7 @@ const selector = (s: ReactFlowState) => ({ height: s.height, }); -export function ConnectionLineWrapper({ containerStyle, style, type, component }: ConnectionLineWrapperProps) { +export function ConnectionLineWrapper({ containerStyle, style, type, component }: ConnectionLineWrapperProps) { const { nodesConnectable, width, height, isValid, inProgress } = useStore(selector, shallow); const renderConnection = !!(width && nodesConnectable && inProgress); @@ -51,15 +51,15 @@ export function ConnectionLineWrapper({ containerStyle, style, type, component } ); } -type ConnectionLineProps = { +type ConnectionLineProps = { type: ConnectionLineType; style?: CSSProperties; - CustomComponent?: ConnectionLineComponent; + CustomComponent?: ConnectionLineComponent; isValid: boolean | null; }; -const ConnectionLine = ({ style, type = ConnectionLineType.Bezier, CustomComponent, isValid }: ConnectionLineProps) => { - const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection(); +const ConnectionLine = ({ style, type = ConnectionLineType.Bezier, CustomComponent, isValid }: ConnectionLineProps) => { + const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection(); if (!inProgress) { return; diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index d04875d1..a5807687 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -259,7 +259,7 @@ export interface ReactFlowProps; /** Styles to be applied to the container of the connection line */ connectionLineContainerStyle?: CSSProperties; /** 'strict' connection mode will only allow you to connect source handles to target handles. From 44c836da3220b66f31f1e6d09ba1c7c442b6404e Mon Sep 17 00:00:00 2001 From: Damian Stasik <920747+damianstasik@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:17:36 +0100 Subject: [PATCH 002/157] fix(system): ensure auto-pan stops when state changes during drag --- packages/system/src/xydrag/XYDrag.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/system/src/xydrag/XYDrag.ts b/packages/system/src/xydrag/XYDrag.ts index eb2ea80a..0921e3ec 100644 --- a/packages/system/src/xydrag/XYDrag.ts +++ b/packages/system/src/xydrag/XYDrag.ts @@ -214,7 +214,13 @@ export function XYDrag voi return; } - const { transform, panBy, autoPanSpeed } = getStoreItems(); + const { transform, panBy, autoPanSpeed, autoPanOnNodeDrag } = getStoreItems(); + + if (!autoPanOnNodeDrag) { + autoPanStarted = false; + cancelAnimationFrame(autoPanId); + return; + } const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed); From ea54d9bcb197d02d248ef3e4eaabc033a43d966a Mon Sep 17 00:00:00 2001 From: Wayne Tee Date: Sat, 1 Feb 2025 12:48:09 +0800 Subject: [PATCH 003/157] fix(react): viewport shifting on node focus --- .changeset/cyan-pianos-lie.md | 5 +++++ packages/react/src/container/ReactFlow/index.tsx | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .changeset/cyan-pianos-lie.md diff --git a/.changeset/cyan-pianos-lie.md b/.changeset/cyan-pianos-lie.md new file mode 100644 index 00000000..2ff7301d --- /dev/null +++ b/.changeset/cyan-pianos-lie.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Fix viewport shifting on node focus diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index 82206fc8..cf250628 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -1,4 +1,4 @@ -import { ForwardedRef, type CSSProperties } from 'react'; +import { ForwardedRef, useCallback, type CSSProperties } from 'react'; import cc from 'classcat'; import { ConnectionLineType, PanOnScrollMode, SelectionMode, infiniteExtent, isMacOs } from '@xyflow/system'; @@ -144,6 +144,7 @@ function ReactFlow( height, colorMode = 'light', debug, + onScroll, ...rest }: ReactFlowProps, ref: ForwardedRef @@ -151,10 +152,20 @@ function ReactFlow( const rfId = id || '1'; const colorModeClassName = useColorModeClass(colorMode); + // Undo scroll events, preventing viewport from shifting when nodes outside of it are focused + const wrapperOnScroll = useCallback( + (e: React.UIEvent) => { + e.currentTarget.scrollTo({ top: 0, left: 0, behavior: 'instant' }); + onScroll?.(e); + }, + [onScroll] + ); + return (
Date: Sun, 9 Feb 2025 05:43:15 +0700 Subject: [PATCH 004/157] fix `lint` command, bump eslint packages --- package.json | 5 - .../src/components/NodeWrapper/index.tsx | 1 - packages/react/src/components/Panel/index.tsx | 2 + packages/system/src/xyhandle/types.ts | 1 - pnpm-lock.yaml | 1202 ++++++++++++----- tooling/eslint-config/package.json | 10 +- 6 files changed, 856 insertions(+), 365 deletions(-) diff --git a/package.json b/package.json index 7a33c404..a86c2b12 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,8 @@ "@changesets/changelog-github": "^0.4.7", "@changesets/cli": "^2.25.0", "@playwright/test": "^1.44.1", - "@typescript-eslint/eslint-plugin": "latest", - "@typescript-eslint/parser": "latest", "concurrently": "^7.6.0", "eslint": "^8.22.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-react": "latest", "prettier": "^2.7.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx index 4b0295e9..bb136161 100644 --- a/packages/react/src/components/NodeWrapper/index.tsx +++ b/packages/react/src/components/NodeWrapper/index.tsx @@ -37,7 +37,6 @@ export function NodeWrapper({ disableKeyboardA11y, rfId, nodeTypes, - nodeExtent, nodeClickDistance, onError, }: NodeWrapperProps) { diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index 83b4a87b..e6dd9edb 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -32,3 +32,5 @@ export const Panel = forwardRef( ); } ); + +Panel.displayName = 'Panel' diff --git a/packages/system/src/xyhandle/types.ts b/packages/system/src/xyhandle/types.ts index 6e468b0a..d3625c9b 100644 --- a/packages/system/src/xyhandle/types.ts +++ b/packages/system/src/xyhandle/types.ts @@ -11,7 +11,6 @@ import { type UpdateConnection, type IsValidConnection, NodeLookup, - ConnectionState, FinalConnectionState, } from '../types'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e2cb0d8..22541966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,27 +17,12 @@ importers: '@playwright/test': specifier: ^1.44.1 version: 1.44.1 - '@typescript-eslint/eslint-plugin': - specifier: latest - version: 8.0.0(@typescript-eslint/parser@8.0.0(eslint@8.43.0)(typescript@5.1.3))(eslint@8.43.0)(typescript@5.1.3) - '@typescript-eslint/parser': - specifier: latest - version: 8.0.0(eslint@8.43.0)(typescript@5.1.3) concurrently: specifier: ^7.6.0 version: 7.6.0 eslint: specifier: ^8.22.0 version: 8.43.0 - eslint-config-prettier: - specifier: ^8.5.0 - version: 8.8.0(eslint@8.43.0) - eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0(eslint@8.43.0))(eslint@8.43.0)(prettier@2.8.8) - eslint-plugin-react: - specifier: latest - version: 7.35.0(eslint@8.43.0) prettier: specifier: ^2.7.1 version: 2.8.8 @@ -443,18 +428,24 @@ importers: tooling/eslint-config: devDependencies: - eslint: - specifier: ^8.22.0 - version: 8.43.0 + '@typescript-eslint/eslint-plugin': + specifier: ^8.23.0 + version: 8.23.0(@typescript-eslint/parser@8.23.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': + specifier: ^8.23.0 + version: 8.23.0(eslint@8.57.0)(typescript@5.4.5) eslint-config-prettier: - specifier: ^8.5.0 - version: 8.8.0(eslint@8.43.0) + specifier: ^10.0.1 + version: 10.0.1(eslint@8.57.0) eslint-config-turbo: - specifier: ^2.0.3 - version: 2.0.3(eslint@8.43.0) + specifier: ^2.4.0 + version: 2.4.0(eslint@8.57.0)(turbo@2.0.3) + eslint-plugin-prettier: + specifier: ^4.2.1 + version: 4.2.1(eslint-config-prettier@10.0.1(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5) eslint-plugin-react: - specifier: ^7.33.2 - version: 7.33.2(eslint@8.43.0) + specifier: ^7.37.4 + version: 7.37.4(eslint@8.57.0) tooling/rollup-config: devDependencies: @@ -2045,16 +2036,13 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@8.0.0': - resolution: {integrity: sha512-STIZdwEQRXAHvNUS6ILDf5z3u95Gc8jzywunxSNqX00OooIemaaNIA0vEgynJlycL5AjabYLLrIyHd4iazyvtg==} + '@typescript-eslint/eslint-plugin@8.23.0': + resolution: {integrity: sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/parser@6.10.0': resolution: {integrity: sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==} @@ -2076,15 +2064,12 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.0.0': - resolution: {integrity: sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==} + '@typescript-eslint/parser@8.23.0': + resolution: {integrity: sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/scope-manager@6.10.0': resolution: {integrity: sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==} @@ -2094,8 +2079,8 @@ packages: resolution: {integrity: sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@8.0.0': - resolution: {integrity: sha512-V0aa9Csx/ZWWv2IPgTfY7T4agYwJyILESu/PVqFtTFz9RIS823mAze+NbnBI8xiwdX3iqeQbcTYlvB04G9wyQw==} + '@typescript-eslint/scope-manager@8.23.0': + resolution: {integrity: sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/type-utils@6.10.0': @@ -2118,14 +2103,12 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@8.0.0': - resolution: {integrity: sha512-mJAFP2mZLTBwAn5WI4PMakpywfWFH5nQZezUQdSKV23Pqo6o9iShQg1hP2+0hJJXP2LnZkWPphdIq4juYYwCeg==} + '@typescript-eslint/type-utils@8.23.0': + resolution: {integrity: sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/types@6.10.0': resolution: {integrity: sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==} @@ -2135,8 +2118,8 @@ packages: resolution: {integrity: sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@8.0.0': - resolution: {integrity: sha512-wgdSGs9BTMWQ7ooeHtu5quddKKs5Z5dS+fHLbrQI+ID0XWJLODGMHRfhwImiHoeO2S5Wir2yXuadJN6/l4JRxw==} + '@typescript-eslint/types@8.23.0': + resolution: {integrity: sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@6.10.0': @@ -2157,14 +2140,11 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.0.0': - resolution: {integrity: sha512-5b97WpKMX+Y43YKi4zVcCVLtK5F98dFls3Oxui8LbnmRsseKenbbDinmvxrWegKDMmlkIq/XHuyy0UGLtpCDKg==} + '@typescript-eslint/typescript-estree@8.23.0': + resolution: {integrity: sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/utils@6.10.0': resolution: {integrity: sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==} @@ -2178,11 +2158,12 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.0.0': - resolution: {integrity: sha512-k/oS/A/3QeGLRvOWCg6/9rATJL5rec7/5s1YmdS0ZU6LHveJyGFwBvLhSRBv6i9xaj7etmosp+l+ViN1I9Aj/Q==} + '@typescript-eslint/utils@8.23.0': + resolution: {integrity: sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' '@typescript-eslint/visitor-keys@6.10.0': resolution: {integrity: sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==} @@ -2192,8 +2173,8 @@ packages: resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@8.0.0': - resolution: {integrity: sha512-oN0K4nkHuOyF3PVMyETbpP5zp6wfyOvm7tWhTMfoqxSSsPmJIh6JNASuZDlODE8eE+0EB9uar+6+vxr9DBTYOA==} + '@typescript-eslint/visitor-keys@8.23.0': + resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.2.0': @@ -2303,8 +2284,8 @@ packages: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} - array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} array-includes@3.1.8: @@ -2326,13 +2307,10 @@ packages: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} engines: {node: '>= 0.4'} - array.prototype.tosorted@1.1.2: - resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} - array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} @@ -2345,6 +2323,10 @@ packages: resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} engines: {node: '>= 0.4'} + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} @@ -2368,9 +2350,6 @@ packages: async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} - asynciterator.prototype@1.0.0: - resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2505,6 +2484,10 @@ packages: resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} engines: {node: '>=6'} + call-bind-apply-helpers@1.0.1: + resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} + engines: {node: '>= 0.4'} + call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} @@ -2512,6 +2495,14 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.3: + resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2868,14 +2859,26 @@ packages: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + data-view-byte-length@1.0.1: resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} engines: {node: '>= 0.4'} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.0: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} @@ -3038,6 +3041,10 @@ packages: resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==} engines: {node: '>=4'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -3087,19 +3094,24 @@ packages: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.0.15: - resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} - - es-iterator-helpers@1.0.19: - resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} es-module-lexer@1.3.1: @@ -3117,6 +3129,10 @@ packages: resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} @@ -3124,6 +3140,10 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -3173,8 +3193,8 @@ packages: peerDependencies: eslint: '>=6.0.0' - eslint-config-prettier@8.8.0: - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + eslint-config-prettier@10.0.1: + resolution: {integrity: sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==} hasBin: true peerDependencies: eslint: '>=7.0.0' @@ -3191,10 +3211,11 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-config-turbo@2.0.3: - resolution: {integrity: sha512-D1+lNOpTFEuAgPWJfRHXHjzvAfO+0TVmORfftmYQNw+uk2UIBjhelhwERBceYFy2oFJnckHsqt69dp/zIM6/0g==} + eslint-config-turbo@2.4.0: + resolution: {integrity: sha512-AiRdy83iwyG4+iMSxXQGUbEClxkGxSlXYH8E2a+0972ao75OWnlDBiiuLMOzDpJubR+QVGC4zonn29AIFCSbFw==} peerDependencies: eslint: '>6.6.0' + turbo: '>2.0.0' eslint-plugin-prettier@4.2.1: resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} @@ -3207,14 +3228,8 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-react@7.33.2: - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - - eslint-plugin-react@7.35.0: - resolution: {integrity: sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==} + eslint-plugin-react@7.37.4: + resolution: {integrity: sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 @@ -3239,10 +3254,11 @@ packages: svelte: optional: true - eslint-plugin-turbo@2.0.3: - resolution: {integrity: sha512-mplP4nYaRvtTNuwF5QTLYKLu0/8LTRsHPgX4ARhaof+QZI2ttglONe1/iJpKB4pg0KqFp7WHziKoJL+s0+CJ1w==} + eslint-plugin-turbo@2.4.0: + resolution: {integrity: sha512-qCgoRi/OTc1VMxab7+sdKiV1xlkY4qjK9sM+kS7+WogrB1DxLguJSQXvk4HA13SD5VmJsq+8FYOw5q4EUk6Ixg==} peerDependencies: eslint: '>6.6.0' + turbo: '>2.0.0' eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} @@ -3252,6 +3268,10 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@8.43.0: resolution: {integrity: sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3477,6 +3497,10 @@ packages: resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} engines: {node: '>= 0.4'} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} @@ -3495,6 +3519,14 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-intrinsic@1.2.7: + resolution: {integrity: sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-stdin@9.0.0: resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} engines: {node: '>=12'} @@ -3519,6 +3551,10 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} @@ -3564,6 +3600,10 @@ packages: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + globalyzer@0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} @@ -3581,6 +3621,10 @@ packages: gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -3626,10 +3670,18 @@ packages: resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} engines: {node: '>= 0.4'} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} @@ -3766,6 +3818,10 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} @@ -3773,6 +3829,10 @@ packages: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -3786,6 +3846,10 @@ packages: is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -3794,6 +3858,10 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + is-buffer@2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} @@ -3817,10 +3885,18 @@ packages: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} engines: {node: '>= 0.4'} + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3834,8 +3910,9 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -3862,8 +3939,9 @@ packages: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} - is-map@2.0.2: - resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} @@ -3880,6 +3958,10 @@ packages: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3906,8 +3988,13 @@ packages: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} - is-set@2.0.2: - resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} @@ -3916,6 +4003,10 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -3928,6 +4019,10 @@ packages: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} @@ -3936,6 +4031,10 @@ packages: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} @@ -3944,6 +4043,10 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -3955,14 +4058,20 @@ packages: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} - is-weakmap@2.0.1: - resolution: {integrity: sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==} + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - is-weakset@2.0.2: - resolution: {integrity: sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} @@ -3981,8 +4090,9 @@ packages: isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} joi@17.11.0: resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==} @@ -4192,6 +4302,10 @@ packages: markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} @@ -4496,6 +4610,10 @@ packages: object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -4504,31 +4622,20 @@ packages: resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} - object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} object.entries@1.1.8: resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} engines: {node: '>= 0.4'} - object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} - engines: {node: '>= 0.4'} - object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - object.hasown@1.1.3: - resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} - - object.values@1.1.7: - resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} - engines: {node: '>= 0.4'} - - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} once@1.4.0: @@ -4560,6 +4667,10 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} @@ -5345,8 +5456,8 @@ packages: redux@5.0.1: resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - reflect.getprototypeof@1.0.4: - resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} regenerator-runtime@0.14.0: @@ -5360,6 +5471,10 @@ packages: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + rehype-parse@8.0.5: resolution: {integrity: sha512-Ds3RglaY/+clEX2U2mHflt7NlMA72KspZ0JLUJgBBLpRddBcEw3H8uYZQliQriku22NZpYMfjDdSgHcjxue24A==} @@ -5487,9 +5602,17 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -5497,6 +5620,10 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -5554,6 +5681,10 @@ packages: resolution: {integrity: sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==} engines: {node: '>= 0.4'} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} engines: {node: '>= 0.4'} @@ -5562,6 +5693,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + sharp@0.32.6: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} @@ -5588,13 +5723,26 @@ packages: shiki@0.14.5: resolution: {integrity: sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==} - side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -5726,16 +5874,17 @@ packages: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} engines: {node: '>=16'} - string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} - - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} @@ -5750,6 +5899,10 @@ packages: string.prototype.trimend@1.0.8: resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} @@ -6015,11 +6168,11 @@ packages: peerDependencies: typescript: '>=4.2.0' - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} + ts-api-utils@2.0.1: + resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' tsconfig-resolver@3.0.1: resolution: {integrity: sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==} @@ -6108,6 +6261,10 @@ packages: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} engines: {node: '>= 0.4'} @@ -6116,6 +6273,10 @@ packages: resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} engines: {node: '>= 0.4'} @@ -6124,6 +6285,10 @@ packages: resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} @@ -6131,6 +6296,10 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + typescript@5.1.3: resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} engines: {node: '>=14.17'} @@ -6157,6 +6326,10 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -6420,12 +6593,17 @@ packages: which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-builtin-type@1.1.3: - resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} - which-collection@1.0.1: - resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} @@ -6450,6 +6628,10 @@ packages: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} + which-typed-array@1.1.18: + resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + engines: {node: '>= 0.4'} + which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -8177,21 +8359,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.0.0(@typescript-eslint/parser@8.0.0(eslint@8.43.0)(typescript@5.1.3))(eslint@8.43.0)(typescript@5.1.3)': + '@typescript-eslint/eslint-plugin@8.23.0(@typescript-eslint/parser@8.23.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.0.0(eslint@8.43.0)(typescript@5.1.3) - '@typescript-eslint/scope-manager': 8.0.0 - '@typescript-eslint/type-utils': 8.0.0(eslint@8.43.0)(typescript@5.1.3) - '@typescript-eslint/utils': 8.0.0(eslint@8.43.0)(typescript@5.1.3) - '@typescript-eslint/visitor-keys': 8.0.0 - eslint: 8.43.0 + '@typescript-eslint/parser': 8.23.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/type-utils': 8.23.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 8.23.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.23.0 + eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.1.3) - optionalDependencies: - typescript: 5.1.3 + ts-api-utils: 2.0.1(typescript@5.4.5) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8221,16 +8402,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.0.0(eslint@8.43.0)(typescript@5.1.3)': + '@typescript-eslint/parser@8.23.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/scope-manager': 8.0.0 - '@typescript-eslint/types': 8.0.0 - '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.1.3) - '@typescript-eslint/visitor-keys': 8.0.0 - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.43.0 - optionalDependencies: - typescript: 5.1.3 + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.23.0 + debug: 4.3.5 + eslint: 8.57.0 + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8244,10 +8424,10 @@ snapshots: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 - '@typescript-eslint/scope-manager@8.0.0': + '@typescript-eslint/scope-manager@8.23.0': dependencies: - '@typescript-eslint/types': 8.0.0 - '@typescript-eslint/visitor-keys': 8.0.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/visitor-keys': 8.23.0 '@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': dependencies: @@ -8273,23 +8453,22 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.0.0(eslint@8.43.0)(typescript@5.1.3)': + '@typescript-eslint/type-utils@8.23.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.1.3) - '@typescript-eslint/utils': 8.0.0(eslint@8.43.0)(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.4.5) + '@typescript-eslint/utils': 8.23.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.5 - ts-api-utils: 1.3.0(typescript@5.1.3) - optionalDependencies: - typescript: 5.1.3 + eslint: 8.57.0 + ts-api-utils: 2.0.1(typescript@5.4.5) + typescript: 5.4.5 transitivePeerDependencies: - - eslint - supports-color '@typescript-eslint/types@6.10.0': {} '@typescript-eslint/types@7.2.0': {} - '@typescript-eslint/types@8.0.0': {} + '@typescript-eslint/types@8.23.0': {} '@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)': dependencies: @@ -8320,18 +8499,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.0.0(typescript@5.1.3)': + '@typescript-eslint/typescript-estree@8.23.0(typescript@5.4.5)': dependencies: - '@typescript-eslint/types': 8.0.0 - '@typescript-eslint/visitor-keys': 8.0.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/visitor-keys': 8.23.0 debug: 4.3.5 - globby: 11.1.0 + fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.1.3) - optionalDependencies: - typescript: 5.1.3 + ts-api-utils: 2.0.1(typescript@5.4.5) + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8363,16 +8541,16 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.0.0(eslint@8.43.0)(typescript@5.1.3)': + '@typescript-eslint/utils@8.23.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) - '@typescript-eslint/scope-manager': 8.0.0 - '@typescript-eslint/types': 8.0.0 - '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.1.3) - eslint: 8.43.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.23.0 + '@typescript-eslint/types': 8.23.0 + '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.4.5) + eslint: 8.57.0 + typescript: 5.4.5 transitivePeerDependencies: - supports-color - - typescript '@typescript-eslint/visitor-keys@6.10.0': dependencies: @@ -8384,10 +8562,10 @@ snapshots: '@typescript-eslint/types': 7.2.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.0.0': + '@typescript-eslint/visitor-keys@8.23.0': dependencies: - '@typescript-eslint/types': 8.0.0 - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.23.0 + eslint-visitor-keys: 4.2.0 '@ungap/structured-clone@1.2.0': {} @@ -8508,13 +8686,10 @@ snapshots: call-bind: 1.0.7 is-array-buffer: 3.0.4 - array-includes@3.1.7: + array-buffer-byte-length@1.0.2: dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - is-string: 1.0.7 + call-bound: 1.0.3 + is-array-buffer: 3.0.5 array-includes@3.1.8: dependencies: @@ -8545,21 +8720,13 @@ snapshots: es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 - array.prototype.flatmap@1.3.2: + array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.5 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.9 es-shim-unscopables: 1.0.2 - array.prototype.tosorted@1.1.2: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - es-shim-unscopables: 1.0.2 - get-intrinsic: 1.2.2 - array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.7 @@ -8589,6 +8756,16 @@ snapshots: is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + is-array-buffer: 3.0.5 + arrify@1.0.1: {} asn1@0.2.6: @@ -8671,10 +8848,6 @@ snapshots: async@3.2.5: {} - asynciterator.prototype@1.0.0: - dependencies: - has-symbols: 1.0.3 - asynckit@0.4.0: {} at-least-node@1.0.0: {} @@ -8829,6 +9002,11 @@ snapshots: cachedir@2.4.0: {} + call-bind-apply-helpers@1.0.1: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + call-bind@1.0.5: dependencies: function-bind: 1.1.2 @@ -8843,6 +9021,18 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.1 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.0 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + call-bound@1.0.3: + dependencies: + call-bind-apply-helpers: 1.0.1 + get-intrinsic: 1.2.7 + callsites@3.1.0: {} camelcase-keys@6.2.2: @@ -9291,18 +9481,36 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + data-view-byte-length@1.0.1: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + data-view-byte-offset@1.0.0: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-data-view: 1.0.2 + dataloader@1.4.0: {} date-fns@2.30.0: @@ -9435,6 +9643,12 @@ snapshots: dset@3.1.2: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + duplexer@0.1.2: {} eastasianwidth@0.2.0: {} @@ -9562,45 +9776,86 @@ snapshots: unbox-primitive: 1.0.2 which-typed-array: 1.1.15 + es-abstract@1.23.9: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.18 + es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 + es-define-property@1.0.1: {} + es-errors@1.3.0: {} - es-iterator-helpers@1.0.15: + es-iterator-helpers@1.2.1: dependencies: - asynciterator.prototype: 1.0.0 - call-bind: 1.0.5 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.22.3 - es-set-tostringtag: 2.0.2 - function-bind: 1.1.2 - get-intrinsic: 1.2.2 - globalthis: 1.0.3 - has-property-descriptors: 1.0.1 - has-proto: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.6 - iterator.prototype: 1.1.2 - safe-array-concat: 1.0.1 - - es-iterator-helpers@1.0.19: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.9 es-errors: 1.3.0 es-set-tostringtag: 2.0.3 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - globalthis: 1.0.3 + get-intrinsic: 1.2.7 + globalthis: 1.0.4 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.2 - safe-array-concat: 1.1.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 es-module-lexer@1.3.1: {} @@ -9616,7 +9871,14 @@ snapshots: es-set-tostringtag@2.0.3: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.7 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.2.7 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -9630,6 +9892,12 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + es6-promise@3.3.1: {} esbuild@0.18.20: @@ -9752,9 +10020,9 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-prettier@8.8.0(eslint@8.43.0): + eslint-config-prettier@10.0.1(eslint@8.57.0): dependencies: - eslint: 8.43.0 + eslint: 8.57.0 eslint-config-prettier@9.0.0(eslint@8.53.0): dependencies: @@ -9764,59 +10032,40 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-turbo@2.0.3(eslint@8.43.0): + eslint-config-turbo@2.4.0(eslint@8.57.0)(turbo@2.0.3): dependencies: - eslint: 8.43.0 - eslint-plugin-turbo: 2.0.3(eslint@8.43.0) + eslint: 8.57.0 + eslint-plugin-turbo: 2.4.0(eslint@8.57.0)(turbo@2.0.3) + turbo: 2.0.3 - eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0(eslint@8.43.0))(eslint@8.43.0)(prettier@2.8.8): + eslint-plugin-prettier@4.2.1(eslint-config-prettier@10.0.1(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5): dependencies: - eslint: 8.43.0 - prettier: 2.8.8 + eslint: 8.57.0 + prettier: 3.2.5 prettier-linter-helpers: 1.0.0 optionalDependencies: - eslint-config-prettier: 8.8.0(eslint@8.43.0) + eslint-config-prettier: 10.0.1(eslint@8.57.0) - eslint-plugin-react@7.33.2(eslint@8.43.0): - dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.2 - doctrine: 2.1.0 - es-iterator-helpers: 1.0.15 - eslint: 8.43.0 - estraverse: 5.3.0 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.7 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.1.7 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.10 - - eslint-plugin-react@7.35.0(eslint@8.43.0): + eslint-plugin-react@7.37.4(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 + array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.19 - eslint: 8.43.0 + es-iterator-helpers: 1.2.1 + eslint: 8.57.0 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.8 object.fromentries: 2.0.8 - object.values: 1.2.0 + object.values: 1.2.1 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.11 + string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 eslint-plugin-svelte@2.35.0(eslint@8.53.0)(svelte@4.2.12): @@ -9861,10 +10110,11 @@ snapshots: - supports-color - ts-node - eslint-plugin-turbo@2.0.3(eslint@8.43.0): + eslint-plugin-turbo@2.4.0(eslint@8.57.0)(turbo@2.0.3): dependencies: dotenv: 16.0.3 - eslint: 8.43.0 + eslint: 8.57.0 + turbo: 2.0.3 eslint-scope@7.2.2: dependencies: @@ -9873,6 +10123,8 @@ snapshots: eslint-visitor-keys@3.4.3: {} + eslint-visitor-keys@4.2.0: {} + eslint@8.43.0: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) @@ -10253,6 +10505,15 @@ snapshots: es-abstract: 1.22.3 functions-have-names: 1.2.3 + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + functions-have-names@1.2.3: {} gensync@1.0.0-beta.2: {} @@ -10274,6 +10535,24 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-intrinsic@1.2.7: + dependencies: + call-bind-apply-helpers: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.0.0 + get-stdin@9.0.0: {} get-stream@5.2.0: @@ -10295,6 +10574,12 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + getos@3.2.1: dependencies: async: 3.2.5 @@ -10347,6 +10632,11 @@ snapshots: dependencies: define-properties: 1.2.1 + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + globalyzer@0.1.0: {} globby@11.1.0: @@ -10373,6 +10663,8 @@ snapshots: dependencies: get-intrinsic: 1.2.4 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} grapheme-splitter@1.0.4: {} @@ -10410,15 +10702,21 @@ snapshots: has-proto@1.0.3: {} + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + has-symbols@1.0.3: {} + has-symbols@1.1.0: {} + has-tostringtag@1.0.0: dependencies: has-symbols: 1.0.3 has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown@2.0.1: dependencies: @@ -10566,6 +10864,12 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + is-array-buffer@3.0.2: dependencies: call-bind: 1.0.7 @@ -10577,6 +10881,12 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + is-arrayish@0.2.1: {} is-arrayish@0.3.2: @@ -10584,12 +10894,16 @@ snapshots: is-async-function@2.0.0: dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 + is-bigint@1.1.0: + dependencies: + has-bigints: 1.0.2 + is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 @@ -10599,6 +10913,11 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.0 + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-buffer@2.0.5: {} is-builtin-module@3.2.1: @@ -10619,25 +10938,36 @@ snapshots: dependencies: is-typed-array: 1.1.13 + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + is-typed-array: 1.1.15 + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.0 + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-docker@3.0.0: {} is-extendable@0.1.1: {} is-extglob@2.1.1: {} - is-finalizationregistry@1.0.2: + is-finalizationregistry@1.1.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.3 is-fullwidth-code-point@3.0.0: {} is-generator-function@1.0.10: dependencies: - has-tostringtag: 1.0.0 + has-tostringtag: 1.0.2 is-glob@4.0.3: dependencies: @@ -10654,7 +10984,7 @@ snapshots: is-interactive@2.0.0: {} - is-map@2.0.2: {} + is-map@2.0.3: {} is-module@1.0.0: {} @@ -10666,6 +10996,11 @@ snapshots: dependencies: has-tostringtag: 1.0.0 + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} is-path-inside@3.0.3: {} @@ -10687,7 +11022,14 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.0 - is-set@2.0.2: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} is-shared-array-buffer@1.0.2: dependencies: @@ -10697,6 +11039,10 @@ snapshots: dependencies: call-bind: 1.0.7 + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.3 + is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -10705,6 +11051,11 @@ snapshots: dependencies: has-tostringtag: 1.0.0 + is-string@1.1.1: + dependencies: + call-bound: 1.0.3 + has-tostringtag: 1.0.2 + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 @@ -10713,6 +11064,12 @@ snapshots: dependencies: has-symbols: 1.0.3 + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.3 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + is-typed-array@1.1.12: dependencies: which-typed-array: 1.1.13 @@ -10721,22 +11078,30 @@ snapshots: dependencies: which-typed-array: 1.1.15 + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.18 + is-typedarray@1.0.0: {} is-unicode-supported@0.1.0: {} is-unicode-supported@1.3.0: {} - is-weakmap@2.0.1: {} + is-weakmap@2.0.2: {} is-weakref@1.0.2: dependencies: call-bind: 1.0.7 - is-weakset@2.0.2: + is-weakref@1.1.1: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bound: 1.0.3 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.3 + get-intrinsic: 1.2.7 is-windows@1.0.2: {} @@ -10750,13 +11115,14 @@ snapshots: isstream@0.1.2: {} - iterator.prototype@1.1.2: + iterator.prototype@1.1.5: dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.4 - set-function-name: 2.0.1 + define-data-property: 1.1.4 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 joi@17.11.0: dependencies: @@ -10819,7 +11185,7 @@ snapshots: array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 - object.values: 1.2.0 + object.values: 1.2.1 keyv@4.5.4: dependencies: @@ -10958,6 +11324,8 @@ snapshots: markdown-table@3.0.3: {} + math-intrinsics@1.1.0: {} + mdast-util-definitions@5.1.2: dependencies: '@types/mdast': 3.0.14 @@ -11416,6 +11784,8 @@ snapshots: object-inspect@1.13.1: {} + object-inspect@1.13.4: {} + object-keys@1.1.1: {} object.assign@4.1.5: @@ -11425,11 +11795,14 @@ snapshots: has-symbols: 1.0.3 object-keys: 1.1.1 - object.entries@1.1.7: + object.assign@4.1.7: dependencies: - call-bind: 1.0.5 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.22.3 + es-object-atoms: 1.0.0 + has-symbols: 1.1.0 + object-keys: 1.1.1 object.entries@1.1.8: dependencies: @@ -11437,12 +11810,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - object.fromentries@2.0.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - object.fromentries@2.0.8: dependencies: call-bind: 1.0.7 @@ -11450,20 +11817,10 @@ snapshots: es-abstract: 1.23.3 es-object-atoms: 1.0.0 - object.hasown@1.1.3: + object.values@1.2.1: dependencies: - define-properties: 1.2.1 - es-abstract: 1.22.3 - - object.values@1.1.7: - dependencies: - call-bind: 1.0.5 - define-properties: 1.2.1 - es-abstract: 1.22.3 - - object.values@1.2.0: - dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 es-object-atoms: 1.0.0 @@ -11506,6 +11863,12 @@ snapshots: outdent@0.5.0: {} + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.2.7 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-filter@2.1.0: dependencies: p-map: 2.1.0 @@ -12285,14 +12648,16 @@ snapshots: redux@5.0.1: {} - reflect.getprototypeof@1.0.4: + reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - get-intrinsic: 1.2.4 - globalthis: 1.0.3 - which-builtin-type: 1.1.3 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.7 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 regenerator-runtime@0.14.0: {} @@ -12309,6 +12674,15 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + rehype-parse@8.0.5: dependencies: '@types/hast': 2.3.7 @@ -12498,8 +12872,21 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + get-intrinsic: 1.2.7 + has-symbols: 1.1.0 + isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + safe-regex-test@1.0.0: dependencies: call-bind: 1.0.7 @@ -12512,6 +12899,12 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-regex: 1.2.1 + safer-buffer@2.1.2: {} sander@0.5.1: @@ -12574,6 +12967,15 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.2 + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + set-function-name@2.0.1: dependencies: define-data-property: 1.1.1 @@ -12587,6 +12989,12 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + sharp@0.32.6: dependencies: color: 4.2.3 @@ -12620,11 +13028,25 @@ snapshots: vscode-oniguruma: 1.7.0 vscode-textmate: 8.0.0 - side-channel@1.0.4: + side-channel-list@1.0.0: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.7 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 side-channel@1.0.6: dependencies: @@ -12633,6 +13055,14 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -12801,37 +13231,36 @@ snapshots: emoji-regex: 10.3.0 strip-ansi: 7.1.0 - string.prototype.matchall@4.0.10: + string.prototype.matchall@4.0.12: dependencies: - call-bind: 1.0.5 + call-bind: 1.0.8 + call-bound: 1.0.3 define-properties: 1.2.1 - es-abstract: 1.22.3 - get-intrinsic: 1.2.2 - has-symbols: 1.0.3 - internal-slot: 1.0.6 - regexp.prototype.flags: 1.5.1 - set-function-name: 2.0.1 - side-channel: 1.0.4 - - string.prototype.matchall@4.0.11: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.23.9 es-errors: 1.3.0 es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.2 + get-intrinsic: 1.2.7 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 - es-abstract: 1.22.3 + es-abstract: 1.23.3 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.0.0 + has-property-descriptors: 1.0.2 string.prototype.trim@1.2.8: dependencies: @@ -12858,6 +13287,13 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.3 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + string.prototype.trimstart@1.0.7: dependencies: call-bind: 1.0.7 @@ -13180,9 +13616,9 @@ snapshots: dependencies: typescript: 5.4.2 - ts-api-utils@1.3.0(typescript@5.1.3): + ts-api-utils@2.0.1(typescript@5.4.5): dependencies: - typescript: 5.1.3 + typescript: 5.4.5 tsconfig-resolver@3.0.1: dependencies: @@ -13266,6 +13702,12 @@ snapshots: es-errors: 1.3.0 is-typed-array: 1.1.13 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.3 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + typed-array-byte-length@1.0.0: dependencies: call-bind: 1.0.7 @@ -13281,6 +13723,14 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + typed-array-byte-offset@1.0.0: dependencies: available-typed-arrays: 1.0.5 @@ -13298,6 +13748,16 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + typed-array-length@1.0.4: dependencies: call-bind: 1.0.7 @@ -13313,6 +13773,15 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.3 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.10 + typescript@5.1.3: {} typescript@5.2.2: {} @@ -13330,6 +13799,13 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.3 + has-bigints: 1.0.2 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + undici-types@5.26.5: {} undici@5.26.5: @@ -13564,27 +14040,36 @@ snapshots: is-string: 1.0.7 is-symbol: 1.0.4 - which-builtin-type@1.1.3: + which-boxed-primitive@1.1.1: dependencies: - function.prototype.name: 1.1.6 - has-tostringtag: 1.0.0 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 - is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 - isarray: 2.0.5 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.1 - which-typed-array: 1.1.13 + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 - which-collection@1.0.1: + which-builtin-type@1.2.1: dependencies: - is-map: 2.0.2 - is-set: 2.0.2 - is-weakmap: 2.0.1 - is-weakset: 2.0.2 + call-bound: 1.0.3 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.18 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 which-module@2.0.1: {} @@ -13616,6 +14101,15 @@ snapshots: gopd: 1.0.1 has-tostringtag: 1.0.2 + which-typed-array@1.1.18: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.3 + for-each: 0.3.3 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@1.3.1: dependencies: isexe: 2.0.0 diff --git a/tooling/eslint-config/package.json b/tooling/eslint-config/package.json index b0ab4c4e..00da90da 100644 --- a/tooling/eslint-config/package.json +++ b/tooling/eslint-config/package.json @@ -5,9 +5,11 @@ "license": "MIT", "main": "src/index.js", "devDependencies": { - "eslint": "^8.22.0", - "eslint-config-prettier": "^8.5.0", - "eslint-config-turbo": "^2.0.3", - "eslint-plugin-react": "^7.33.2" + "eslint-config-prettier": "^10.0.1", + "eslint-config-turbo": "^2.4.0", + "eslint-plugin-react": "^7.37.4", + "@typescript-eslint/eslint-plugin": "^8.23.0", + "@typescript-eslint/parser": "^8.23.0", + "eslint-plugin-prettier": "^4.2.1" } } From 693fe1ff5fe31179fe0343b628fc2681b49679a9 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Mon, 10 Feb 2025 19:24:49 +0700 Subject: [PATCH 005/157] Update package.json --- packages/react/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/package.json b/packages/react/package.json index fb572c1a..1cdf428c 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -28,6 +28,7 @@ "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", "exports": { + "./package.json": "./package.json", ".": { "node": { "types": "./dist/esm/index.d.ts", From e8e0d684957b95d53a6cc11598c8755ff02117c7 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 10 Feb 2025 18:40:38 +0100 Subject: [PATCH 006/157] chore(changeset): add --- .changeset/shiny-windows-remain.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/shiny-windows-remain.md diff --git a/.changeset/shiny-windows-remain.md b/.changeset/shiny-windows-remain.md new file mode 100644 index 00000000..6b8d6372 --- /dev/null +++ b/.changeset/shiny-windows-remain.md @@ -0,0 +1,7 @@ +--- +'@xyflow/react': patch +'@xyflow/system': patch +'@xyflow/eslint-config': patch +--- + +repair lint command From 12d859fe297593d44cf8493a4d6bf2c664b9139c Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 10 Feb 2025 18:45:17 +0100 Subject: [PATCH 007/157] chore(changeset): add --- .changeset/polite-hounds-yawn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/polite-hounds-yawn.md diff --git a/.changeset/polite-hounds-yawn.md b/.changeset/polite-hounds-yawn.md new file mode 100644 index 00000000..790decaf --- /dev/null +++ b/.changeset/polite-hounds-yawn.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Add package.json to exports From d8ab3bf0bd8dc79a15dc8b31167f4b194275bffc Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 13:59:17 +0100 Subject: [PATCH 008/157] chore(hooks): tsdoc update --- packages/react/package.json | 2 +- .../Background/Background.tsx | 53 ++++++ .../additional-components/Background/types.ts | 3 +- .../additional-components/Controls/types.ts | 3 +- .../additional-components/MiniMap/MiniMap.tsx | 18 +- .../MiniMap/MiniMapNodes.tsx | 18 +- .../additional-components/MiniMap/types.ts | 3 +- .../NodeResizer/NodeResizeControl.tsx | 6 +- .../NodeResizer/types.ts | 9 +- .../NodeToolbar/types.ts | 6 +- .../src/components/BatchProvider/index.tsx | 8 +- .../src/components/BatchProvider/useQueue.ts | 28 +-- .../src/components/EdgeWrapper/index.tsx | 20 +-- packages/react/src/components/Edges/index.ts | 8 +- .../react/src/components/Handle/index.tsx | 6 +- .../src/components/NodeWrapper/index.tsx | 6 +- .../components/NodeWrapper/useNodeObserver.ts | 6 +- .../src/components/NodeWrapper/utils.tsx | 6 +- packages/react/src/components/Nodes/utils.ts | 10 +- .../src/components/NodesSelection/index.tsx | 6 +- packages/react/src/components/Panel/index.tsx | 3 +- .../src/components/StoreUpdater/index.tsx | 8 +- .../EdgeRenderer/MarkerDefinitions.tsx | 8 +- .../src/container/NodeRenderer/index.tsx | 48 ++--- packages/react/src/container/Pane/index.tsx | 12 +- .../react/src/container/ReactFlow/Wrapper.tsx | 6 +- packages/react/src/contexts/NodeIdContext.ts | 28 +++ packages/react/src/hooks/useConnection.ts | 21 ++- packages/react/src/hooks/useEdges.ts | 14 +- packages/react/src/hooks/useInternalNode.ts | 22 ++- packages/react/src/hooks/useKeyPress.ts | 66 +++++-- .../react/src/hooks/useMoveSelectedNodes.ts | 6 +- .../react/src/hooks/useNodeConnections.ts | 18 +- packages/react/src/hooks/useNodes.ts | 15 +- packages/react/src/hooks/useNodesData.ts | 16 +- .../react/src/hooks/useNodesEdgesState.ts | 64 ++++++- .../react/src/hooks/useNodesInitialized.ts | 41 ++++- .../react/src/hooks/useOnSelectionChange.ts | 34 +++- .../react/src/hooks/useOnViewportChange.ts | 20 ++- packages/react/src/hooks/useReactFlow.ts | 25 ++- packages/react/src/hooks/useStore.ts | 25 ++- .../react/src/hooks/useUpdateNodeInternals.ts | 40 ++++- packages/react/src/hooks/useViewport.ts | 25 ++- packages/react/src/hooks/useVisibleNodeIds.ts | 4 +- packages/react/src/store/index.ts | 52 +++--- packages/react/src/types/component-props.ts | 165 ++++++++++++------ packages/react/src/utils/changes.ts | 94 +++++----- pnpm-lock.yaml | 48 +++++ tooling/eslint-config/package.json | 9 +- tooling/eslint-config/src/index.js | 4 +- 50 files changed, 895 insertions(+), 271 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index 1cdf428c..af284012 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -57,7 +57,7 @@ "build": "rollup --config node:@xyflow/rollup-config --environment NODE_ENV:production && npm run css", "css": "postcss src/styles/{base,style}.css --config ./../../tooling/postcss-config/ --dir dist ", "css-watch": "pnpm css --watch", - "lint": "eslint --ext .js,.jsx,.ts,.tsx src", + "lint": "eslint --ext .js,.jsx,.ts,.tsx src --fix", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/packages/react/src/additional-components/Background/Background.tsx b/packages/react/src/additional-components/Background/Background.tsx index e4470f10..ee89624d 100644 --- a/packages/react/src/additional-components/Background/Background.tsx +++ b/packages/react/src/additional-components/Background/Background.tsx @@ -90,4 +90,57 @@ function BackgroundComponent({ BackgroundComponent.displayName = 'Background'; +/** + * The `` component makes it convenient to render different types of backgrounds common in node-based UIs. It comes with three variants: lines, dots and cross. + * + * @example + * + * A simple example of how to use the Background component. + * + * ```tsx + * import { useState } from 'react'; + * import { ReactFlow, Background, BackgroundVariant } from '@xyflow/react'; + * + * export default function Flow() { + * return ( + * + * + * + * ); + * } + * ``` + * + * @example + * + * In this example you can see how to combine multiple backgrounds + * + * ```tsx + * import { ReactFlow, Background, BackgroundVariant } from '@xyflow/react'; + * import '@xyflow/react/dist/style.css'; + * + * export default function Flow() { + * return ( + * + * + * + * + * ); + * } + * ``` + * + * @remarks + * + * When combining multiple components it’s important to give each of them a unique id prop! + * + */ export const Background = memo(BackgroundComponent); diff --git a/packages/react/src/additional-components/Background/types.ts b/packages/react/src/additional-components/Background/types.ts index 0a035aae..9d1cd67b 100644 --- a/packages/react/src/additional-components/Background/types.ts +++ b/packages/react/src/additional-components/Background/types.ts @@ -24,7 +24,8 @@ export type BackgroundProps = { offset?: number | [number, number]; /** Line width of the Line pattern */ lineWidth?: number; - /** Variant of the pattern + /** + * Variant of the pattern * @example BackgroundVariant.Lines, BackgroundVariant.Dots, BackgroundVariant.Cross * 'lines', 'dots', 'cross' */ diff --git a/packages/react/src/additional-components/Controls/types.ts b/packages/react/src/additional-components/Controls/types.ts index f6ea0f8b..c36275d9 100644 --- a/packages/react/src/additional-components/Controls/types.ts +++ b/packages/react/src/additional-components/Controls/types.ts @@ -20,7 +20,8 @@ export type ControlProps = { onFitView?: () => void; /** Callback when interactivity is toggled */ onInteractiveChange?: (interactiveStatus: boolean) => void; - /** Position of the controls on the pane + /** + * Position of the controls on the pane * @example PanelPosition.TopLeft, PanelPosition.TopRight, * PanelPosition.BottomLeft, PanelPosition.BottomRight */ diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index bd7d6634..2f749395 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -44,8 +44,10 @@ function MiniMapComponent({ nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth, - // We need to rename the prop to be `CapitalCase` so that JSX will render it as - // a component properly. + /* + * We need to rename the prop to be `CapitalCase` so that JSX will render it as + * a component properly. + */ nodeComponent, bgColor, maskColor, @@ -111,16 +113,16 @@ function MiniMapComponent({ const onSvgClick = onClick ? (event: MouseEvent) => { - const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; - onClick(event, { x, y }); - } + const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; + onClick(event, { x, y }); + } : undefined; const onSvgNodeClick = onNodeClick ? useCallback((event: MouseEvent, nodeId: string) => { - const node = store.getState().nodeLookup.get(nodeId)!; - onNodeClick(event, node); - }, []) + const node = store.getState().nodeLookup.get(nodeId)!; + onNodeClick(event, node); + }, []) : undefined; return ( diff --git a/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx b/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx index 87fd21e5..2c314289 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx @@ -21,8 +21,10 @@ function MiniMapNodes({ nodeClassName = '', nodeBorderRadius = 5, nodeStrokeWidth, - // We need to rename the prop to be `CapitalCase` so that JSX will render it as - // a component properly. + /* + * We need to rename the prop to be `CapitalCase` so that JSX will render it as + * a component properly. + */ nodeComponent: NodeComponent = MiniMapNode, onClick, }: MiniMapNodesProps) { @@ -36,11 +38,13 @@ function MiniMapNodes({ return ( <> {nodeIds.map((nodeId) => ( - // The split of responsibilities between MiniMapNodes and - // NodeComponentWrapper may appear weird. However, it’s designed to - // minimize the cost of updates when individual nodes change. - // - // For more details, see a similar commit in `NodeRenderer/index.tsx`. + /* + * The split of responsibilities between MiniMapNodes and + * NodeComponentWrapper may appear weird. However, it’s designed to + * minimize the cost of updates when individual nodes change. + * + * For more details, see a similar commit in `NodeRenderer/index.tsx`. + */ key={nodeId} id={nodeId} diff --git a/packages/react/src/additional-components/MiniMap/types.ts b/packages/react/src/additional-components/MiniMap/types.ts index 4bfd1a51..c6d11ba8 100644 --- a/packages/react/src/additional-components/MiniMap/types.ts +++ b/packages/react/src/additional-components/MiniMap/types.ts @@ -27,7 +27,8 @@ export type MiniMapProps = Omit & { - /** Position of the control + /** + * Position of the control * @example ControlPosition.TopLeft, ControlPosition.TopRight, * ControlPosition.BottomLeft, ControlPosition.BottomRight */ position?: ControlPosition; - /** Variant of the control + /** + * Variant of the control * @example ResizeControlVariant.Handle, ResizeControlVariant.Line */ variant?: ResizeControlVariant; diff --git a/packages/react/src/additional-components/NodeToolbar/types.ts b/packages/react/src/additional-components/NodeToolbar/types.ts index 4de679bd..00bec37c 100644 --- a/packages/react/src/additional-components/NodeToolbar/types.ts +++ b/packages/react/src/additional-components/NodeToolbar/types.ts @@ -6,14 +6,16 @@ export type NodeToolbarProps = HTMLAttributes & { nodeId?: string | string[]; /** If true, node toolbar is visible even if node is not selected */ isVisible?: boolean; - /** Position of the toolbar relative to the node + /** + * Position of the toolbar relative to the node * @example Position.TopLeft, Position.TopRight, * Position.BottomLeft, Position.BottomRight */ position?: Position; /** Offset the toolbar from the node */ offset?: number; - /** Align the toolbar relative to the node + /** + * Align the toolbar relative to the node * @example Align.Start, Align.Center, Align.End */ align?: Align; diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 1dbab718..5a5d1ed3 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -30,9 +30,11 @@ export function BatchProvider[]) => { const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState(); - // This is essentially an `Array.reduce` in imperative clothing. Processing - // this queue is a relatively hot path so we'd like to avoid the overhead of - // array methods where we can. + /* + * This is essentially an `Array.reduce` in imperative clothing. Processing + * this queue is a relatively hot path so we'd like to avoid the overhead of + * array methods where we can. + */ let next = nodes as NodeType[]; for (const payload of queueItems) { next = typeof payload === 'function' ? payload(next) : payload; diff --git a/packages/react/src/components/BatchProvider/useQueue.ts b/packages/react/src/components/BatchProvider/useQueue.ts index c33208d7..b1f9f793 100644 --- a/packages/react/src/components/BatchProvider/useQueue.ts +++ b/packages/react/src/components/BatchProvider/useQueue.ts @@ -12,21 +12,27 @@ import { Queue, QueueItem } from './types'; * @returns a Queue object */ export function useQueue(runQueue: (items: QueueItem[]) => void) { - // Because we're using a ref above, we need some way to let React know when to - // actually process the queue. We increment this number any time we mutate the - // queue, creating a new state to trigger the layout effect below. - // Using a boolean dirty flag here instead would lead to issues related to - // automatic batching. (https://github.com/xyflow/xyflow/issues/4779) + /* + * Because we're using a ref above, we need some way to let React know when to + * actually process the queue. We increment this number any time we mutate the + * queue, creating a new state to trigger the layout effect below. + * Using a boolean dirty flag here instead would lead to issues related to + * automatic batching. (https://github.com/xyflow/xyflow/issues/4779) + */ const [serial, setSerial] = useState(BigInt(0)); - // A reference of all the batched updates to process before the next render. We - // want a reference here so multiple synchronous calls to `setNodes` etc can be - // batched together. + /* + * A reference of all the batched updates to process before the next render. We + * want a reference here so multiple synchronous calls to `setNodes` etc can be + * batched together. + */ const [queue] = useState(() => createQueue(() => setSerial(n => n + BigInt(1)))); - // Layout effects are guaranteed to run before the next render which means we - // shouldn't run into any issues with stale state or weird issues that come from - // rendering things one frame later than expected (we used to use `setTimeout`). + /* + * Layout effects are guaranteed to run before the next render which means we + * shouldn't run into any issues with stale state or weird issues that come from + * rendering things one frame later than expected (we used to use `setTimeout`). + */ useIsomorphicLayoutEffect(() => { const queueItems = queue.get(); diff --git a/packages/react/src/components/EdgeWrapper/index.tsx b/packages/react/src/components/EdgeWrapper/index.tsx index f50ed4b9..2d3754fd 100644 --- a/packages/react/src/components/EdgeWrapper/index.tsx +++ b/packages/react/src/components/EdgeWrapper/index.tsx @@ -136,28 +136,28 @@ export function EdgeWrapper({ const onEdgeDoubleClick = onDoubleClick ? (event: React.MouseEvent) => { - onDoubleClick(event, { ...edge }); - } + onDoubleClick(event, { ...edge }); + } : undefined; const onEdgeContextMenu = onContextMenu ? (event: React.MouseEvent) => { - onContextMenu(event, { ...edge }); - } + onContextMenu(event, { ...edge }); + } : undefined; const onEdgeMouseEnter = onMouseEnter ? (event: React.MouseEvent) => { - onMouseEnter(event, { ...edge }); - } + onMouseEnter(event, { ...edge }); + } : undefined; const onEdgeMouseMove = onMouseMove ? (event: React.MouseEvent) => { - onMouseMove(event, { ...edge }); - } + onMouseMove(event, { ...edge }); + } : undefined; const onEdgeMouseLeave = onMouseLeave ? (event: React.MouseEvent) => { - onMouseLeave(event, { ...edge }); - } + onMouseLeave(event, { ...edge }); + } : undefined; const onKeyDown = (event: KeyboardEvent) => { diff --git a/packages/react/src/components/Edges/index.ts b/packages/react/src/components/Edges/index.ts index 21af9667..88b274eb 100644 --- a/packages/react/src/components/Edges/index.ts +++ b/packages/react/src/components/Edges/index.ts @@ -1,6 +1,8 @@ -// We distinguish between internal and exported edges -// The internal edges are used directly like custom edges and always get an id, source and target props -// If you import an edge from the library, the id is optional and source and target are not used at all +/* + * We distinguish between internal and exported edges + * The internal edges are used directly like custom edges and always get an id, source and target props + * If you import an edge from the library, the id is optional and source and target are not used at all + */ export { SimpleBezierEdge, SimpleBezierEdgeInternal } from './SimpleBezierEdge'; export { SmoothStepEdge, SmoothStepEdgeInternal } from './SmoothStepEdge'; diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index cc86e189..70e52dbe 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -228,8 +228,10 @@ function HandleComponent( connectingfrom: connectingFrom, connectingto: connectingTo, valid, - // shows where you can start a connection from - // and where you can end it while connecting + /* + * shows where you can start a connection from + * and where you can end it while connecting + */ connectionindicator: isConnectable && (!connectionInProcess || isPossibleEndHandle) && diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx index bb136161..5c0ce08b 100644 --- a/packages/react/src/components/NodeWrapper/index.tsx +++ b/packages/react/src/components/NodeWrapper/index.tsx @@ -108,8 +108,10 @@ export function NodeWrapper({ const { selectNodesOnDrag, nodeDragThreshold } = store.getState(); if (isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0)) { - // this handler gets called by XYDrag on drag start when selectNodesOnDrag=true - // here we only need to call it when selectNodesOnDrag=false + /* + * this handler gets called by XYDrag on drag start when selectNodesOnDrag=true + * here we only need to call it when selectNodesOnDrag=false + */ handleNodeClick({ id, store, diff --git a/packages/react/src/components/NodeWrapper/useNodeObserver.ts b/packages/react/src/components/NodeWrapper/useNodeObserver.ts index 2c2910fd..de1d31e7 100644 --- a/packages/react/src/components/NodeWrapper/useNodeObserver.ts +++ b/packages/react/src/components/NodeWrapper/useNodeObserver.ts @@ -49,8 +49,10 @@ export function useNodeObserver({ useEffect(() => { if (nodeRef.current) { - // when the user programmatically changes the source or handle position, we need to update the internals - // to make sure the edges are updated correctly + /* + * when the user programmatically changes the source or handle position, we need to update the internals + * to make sure the edges are updated correctly + */ const typeChanged = prevType.current !== nodeType; const sourcePosChanged = prevSourcePosition.current !== node.sourcePosition; const targetPosChanged = prevTargetPosition.current !== node.targetPosition; diff --git a/packages/react/src/components/NodeWrapper/utils.tsx b/packages/react/src/components/NodeWrapper/utils.tsx index c8c7d5c7..8c699c64 100644 --- a/packages/react/src/components/NodeWrapper/utils.tsx +++ b/packages/react/src/components/NodeWrapper/utils.tsx @@ -23,9 +23,9 @@ export const builtinNodeTypes: NodeTypes = { export function getNodeInlineStyleDimensions( node: InternalNode ): { - width: number | string | undefined; - height: number | string | undefined; -} { + width: number | string | undefined; + height: number | string | undefined; + } { if (node.internals.handleBounds === undefined) { return { width: node.width ?? node.initialWidth ?? node.style?.width, diff --git a/packages/react/src/components/Nodes/utils.ts b/packages/react/src/components/Nodes/utils.ts index 81939bbc..146e05f8 100644 --- a/packages/react/src/components/Nodes/utils.ts +++ b/packages/react/src/components/Nodes/utils.ts @@ -4,10 +4,12 @@ import { errorMessages } from '@xyflow/system'; import type { ReactFlowState } from '../../types'; -// this handler is called by -// 1. the click handler when node is not draggable or selectNodesOnDrag = false -// or -// 2. the on drag start handler when node is draggable and selectNodesOnDrag = true +/* + * this handler is called by + * 1. the click handler when node is not draggable or selectNodesOnDrag = false + * or + * 2. the on drag start handler when node is draggable and selectNodesOnDrag = true + */ export function handleNodeClick({ id, store, diff --git a/packages/react/src/components/NodesSelection/index.tsx b/packages/react/src/components/NodesSelection/index.tsx index ecaef17b..ae587b56 100644 --- a/packages/react/src/components/NodesSelection/index.tsx +++ b/packages/react/src/components/NodesSelection/index.tsx @@ -61,9 +61,9 @@ export function NodesSelection({ const onContextMenu = onSelectionContextMenu ? (event: MouseEvent) => { - const selectedNodes = store.getState().nodes.filter((n) => n.selected); - onSelectionContextMenu(event, selectedNodes); - } + const selectedNodes = store.getState().nodes.filter((n) => n.selected); + onSelectionContextMenu(event, selectedNodes); + } : undefined; const onKeyDown = (event: KeyboardEvent) => { diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index e6dd9edb..63695928 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -6,7 +6,8 @@ import { useStore } from '../../hooks/useStore'; import type { ReactFlowState } from '../../types'; export type PanelProps = HTMLAttributes & { - /** Set position of the panel + /** + * Set position of the panel * @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' */ position?: PanelPosition; diff --git a/packages/react/src/components/StoreUpdater/index.tsx b/packages/react/src/components/StoreUpdater/index.tsx index cac8df0e..e3a61ab2 100644 --- a/packages/react/src/components/StoreUpdater/index.tsx +++ b/packages/react/src/components/StoreUpdater/index.tsx @@ -94,9 +94,11 @@ const selector = (s: ReactFlowState) => ({ }); const initPrevValues = { - // these are values that are also passed directly to other components - // than the StoreUpdater. We can reduce the number of setStore calls - // by setting the same values here as prev fields. + /* + * these are values that are also passed directly to other components + * than the StoreUpdater. We can reduce the number of setStore calls + * by setting the same values here as prev fields. + */ translateExtent: infiniteExtent, nodeOrigin: defaultNodeOrigin, minZoom: 0.5, diff --git a/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx b/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx index 5b6194c5..17b5950c 100644 --- a/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx +++ b/packages/react/src/container/EdgeRenderer/MarkerDefinitions.tsx @@ -42,9 +42,11 @@ const Marker = ({ ); }; -// when you have multiple flows on a page and you hide the first one, the other ones have no markers anymore -// when they do have markers with the same ids. To prevent this the user can pass a unique id to the react flow wrapper -// that we can then use for creating our unique marker ids +/* + * when you have multiple flows on a page and you hide the first one, the other ones have no markers anymore + * when they do have markers with the same ids. To prevent this the user can pass a unique id to the react flow wrapper + * that we can then use for creating our unique marker ids + */ const MarkerDefinitions = ({ defaultColor, rfId }: MarkerDefinitionsProps) => { const edges = useStore((s) => s.edges); const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions); diff --git a/packages/react/src/container/NodeRenderer/index.tsx b/packages/react/src/container/NodeRenderer/index.tsx index 7b0bd131..02126d73 100644 --- a/packages/react/src/container/NodeRenderer/index.tsx +++ b/packages/react/src/container/NodeRenderer/index.tsx @@ -44,29 +44,31 @@ function NodeRendererComponent(props: NodeRendererProps {nodeIds.map((nodeId) => { return ( - // The split of responsibilities between NodeRenderer and - // NodeComponentWrapper may appear weird. However, it’s designed to - // minimize the cost of updates when individual nodes change. - // - // For example, when you’re dragging a single node, that node gets - // updated multiple times per second. If `NodeRenderer` were to update - // every time, it would have to re-run the `nodes.map()` loop every - // time. This gets pricey with hundreds of nodes, especially if every - // loop cycle does more than just rendering a JSX element! - // - // As a result of this choice, we took the following implementation - // decisions: - // - NodeRenderer subscribes *only* to node IDs – and therefore - // rerender *only* when visible nodes are added or removed. - // - NodeRenderer performs all operations the result of which can be - // shared between nodes (such as creating the `ResizeObserver` - // instance, or subscribing to `selector`). This means extra prop - // drilling into `NodeComponentWrapper`, but it means we need to run - // these operations only once – instead of once per node. - // - Any operations that you’d normally write inside `nodes.map` are - // moved into `NodeComponentWrapper`. This ensures they are - // memorized – so if `NodeRenderer` *has* to rerender, it only - // needs to regenerate the list of nodes, nothing else. + /* + * The split of responsibilities between NodeRenderer and + * NodeComponentWrapper may appear weird. However, it’s designed to + * minimize the cost of updates when individual nodes change. + * + * For example, when you’re dragging a single node, that node gets + * updated multiple times per second. If `NodeRenderer` were to update + * every time, it would have to re-run the `nodes.map()` loop every + * time. This gets pricey with hundreds of nodes, especially if every + * loop cycle does more than just rendering a JSX element! + * + * As a result of this choice, we took the following implementation + * decisions: + * - NodeRenderer subscribes *only* to node IDs – and therefore + * rerender *only* when visible nodes are added or removed. + * - NodeRenderer performs all operations the result of which can be + * shared between nodes (such as creating the `ResizeObserver` + * instance, or subscribing to `selector`). This means extra prop + * drilling into `NodeComponentWrapper`, but it means we need to run + * these operations only once – instead of once per node. + * - Any operations that you’d normally write inside `nodes.map` are + * moved into `NodeComponentWrapper`. This ensures they are + * memorized – so if `NodeRenderer` *has* to rerender, it only + * needs to regenerate the list of nodes, nothing else. + */ key={nodeId} id={nodeId} diff --git a/packages/react/src/container/Pane/index.tsx b/packages/react/src/container/Pane/index.tsx index aeadde03..91459539 100644 --- a/packages/react/src/container/Pane/index.tsx +++ b/packages/react/src/container/Pane/index.tsx @@ -233,8 +233,10 @@ export function Pane({ (event.target as Partial)?.releasePointerCapture?.(event.pointerId); const { userSelectionRect } = store.getState(); - // We only want to trigger click functions when in selection mode if - // the user did not move the mouse. + /* + * We only want to trigger click functions when in selection mode if + * the user did not move the mouse. + */ if (!userSelectionActive && userSelectionRect && event.target === container.current) { onClick?.(event); } @@ -246,8 +248,10 @@ export function Pane({ }); onSelectionEnd?.(event); - // If the user kept holding the selectionKey during the selection, - // we need to reset the selectionInProgress, so the next click event is not prevented + /* + * If the user kept holding the selectionKey during the selection, + * we need to reset the selectionInProgress, so the next click event is not prevented + */ if (selectionKeyPressed || selectionOnDrag) { selectionInProgress.current = false; } diff --git a/packages/react/src/container/ReactFlow/Wrapper.tsx b/packages/react/src/container/ReactFlow/Wrapper.tsx index 5856809a..71a84316 100644 --- a/packages/react/src/container/ReactFlow/Wrapper.tsx +++ b/packages/react/src/container/ReactFlow/Wrapper.tsx @@ -31,8 +31,10 @@ export function Wrapper({ const isWrapped = useContext(StoreContext); if (isWrapped) { - // we need to wrap it with a fragment because it's not allowed for children to be a ReactNode - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051 + /* + * we need to wrap it with a fragment because it's not allowed for children to be a ReactNode + * https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18051 + */ return <>{children}; } diff --git a/packages/react/src/contexts/NodeIdContext.ts b/packages/react/src/contexts/NodeIdContext.ts index 28a14b78..b5811ad6 100644 --- a/packages/react/src/contexts/NodeIdContext.ts +++ b/packages/react/src/contexts/NodeIdContext.ts @@ -4,6 +4,34 @@ export const NodeIdContext = createContext(null); export const Provider = NodeIdContext.Provider; export const Consumer = NodeIdContext.Consumer; +/** + * You can use this hook to get the id of the node it is used inside. It is useful + *if you need the node's id deeper in the render tree but don't want to manually + *drill down the id as a prop. + * + * @public + * @returns id of the node + * + * @example + *```jsx + *import { useNodeId } from '@xyflow/react'; + * + *export default function CustomNode() { + * return ( + *
+ * This node has an id of + * + *
+ * ); + *} + * + *function NodeIdDisplay() { + * const nodeId = useNodeId(); + * + * return {nodeId}; + *} + *``` + */ export const useNodeId = (): string | null => { const nodeId = useContext(NodeIdContext); return nodeId; diff --git a/packages/react/src/hooks/useConnection.ts b/packages/react/src/hooks/useConnection.ts index 94db5140..8992d767 100644 --- a/packages/react/src/hooks/useConnection.ts +++ b/packages/react/src/hooks/useConnection.ts @@ -24,9 +24,28 @@ function getSelector {connection ? `Someone is trying to make a connection from ${connection.fromNode} to this one.` : 'There are currently no incoming connections!'} + * + *
+ * ); + * } + * ``` + * * @returns ConnectionState */ export function useConnection>>( diff --git a/packages/react/src/hooks/useEdges.ts b/packages/react/src/hooks/useEdges.ts index 3ed9de39..731bf845 100644 --- a/packages/react/src/hooks/useEdges.ts +++ b/packages/react/src/hooks/useEdges.ts @@ -6,10 +6,22 @@ import type { Edge, ReactFlowState } from '../types'; const edgesSelector = (state: ReactFlowState) => state.edges; /** - * Hook for getting the current edges from the store. + * This hook returns an array of the current edges. Components that use this hook + *will re-render **whenever any edge changes**. * * @public * @returns An array of edges + * + * @example + * ```tsx + *import { useEdges } from '@xyflow/react'; + * + *export default function () { + * const edges = useEdges(); + * + * return
There are currently {edges.length} edges!
; + *} + *``` */ export function useEdges(): EdgeType[] { const edges = useStore(edgesSelector, shallow) as EdgeType[]; diff --git a/packages/react/src/hooks/useInternalNode.ts b/packages/react/src/hooks/useInternalNode.ts index d16d697b..bfdc74f9 100644 --- a/packages/react/src/hooks/useInternalNode.ts +++ b/packages/react/src/hooks/useInternalNode.ts @@ -5,11 +5,31 @@ import { useStore } from './useStore'; import type { InternalNode, Node } from '../types'; /** - * Hook for getting an internal node by id + * This hook returns the internal representation of a specific node. Components that use this hook + *will re-render **whenever the node changes**, including when a node is selected + *or moved. * * @public * @param id - id of the node * @returns array with visible node ids + * + * @example + * ```tsx + *import { useInternalNode } from '@xyflow/react'; + * + *export default function () { + * const internalNode = useInternalNode('node-1'); + * const absolutePosition = internalNode.internals.positionAbsolute; + * + * return ( + *
+ * The absolute position of the node is at: + *

x: {absolutePosition.x}

+ *

y: {absolutePosition.y}

+ *
+ * ); + *} + *``` */ export function useInternalNode(id: string): InternalNode | undefined { const node = useStore( diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index 8bce0564..6f2d01c3 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -13,18 +13,38 @@ export type UseKeyPressOptions = { const defaultDoc = typeof document !== 'undefined' ? document : null; /** - * Hook for handling key events. + * This hook lets you listen for specific key codes and tells you whether they are + *currently pressed or not. * * @public * @param param.keyCode - The key code (string or array of strings) to use * @param param.options - Options * @returns boolean + * + * @example + * ```tsx + *import { useKeyPress } from '@xyflow/react'; + * + *export default function () { + * const spacePressed = useKeyPress('Space'); + * const cmdAndSPressed = useKeyPress(['Meta+s', 'Strg+s']); + * + * return ( + *
+ * {spacePressed &&

Space pressed!

} + * {cmdAndSPressed &&

Cmd + S pressed!

} + *
+ * ); + *} + *``` */ export function useKeyPress( - // the keycode can be a string 'a' or an array of strings ['a', 'a+d'] - // a string means a single key 'a' or a combination when '+' is used 'a+d' - // an array means different possibilites. Explainer: ['a', 'd+s'] here the - // user can use the single key 'a' or the combination 'd' + 's' + /* + * the keycode can be a string 'a' or an array of strings ['a', 'a+d'] + * a string means a single key 'a' or a combination when '+' is used 'a+d' + * an array means different possibilites. Explainer: ['a', 'd+s'] here the + * user can use the single key 'a' or the combination 'd' + 's' + */ keyCode: KeyCode | null = null, options: UseKeyPressOptions = { target: defaultDoc, actInsideInputWithModifier: true } ): boolean { @@ -36,20 +56,24 @@ export function useKeyPress( // we need to remember the pressed keys in order to support combinations const pressedKeys = useRef(new Set([])); - // keyCodes = array with single keys [['a']] or key combinations [['a', 's']] - // keysToWatch = array with all keys flattened ['a', 'd', 'ShiftLeft'] - // used to check if we store event.code or event.key. When the code is in the list of keysToWatch - // we use the code otherwise the key. Explainer: When you press the left "command" key, the code is "MetaLeft" - // and the key is "Meta". We want users to be able to pass keys and codes so we assume that the key is meant when - // we can't find it in the list of keysToWatch. + /* + * keyCodes = array with single keys [['a']] or key combinations [['a', 's']] + * keysToWatch = array with all keys flattened ['a', 'd', 'ShiftLeft'] + * used to check if we store event.code or event.key. When the code is in the list of keysToWatch + * we use the code otherwise the key. Explainer: When you press the left "command" key, the code is "MetaLeft" + * and the key is "Meta". We want users to be able to pass keys and codes so we assume that the key is meant when + * we can't find it in the list of keysToWatch. + */ const [keyCodes, keysToWatch] = useMemo<[Array, Keys]>(() => { if (keyCode !== null) { const keyCodeArr = Array.isArray(keyCode) ? keyCode : [keyCode]; const keys = keyCodeArr .filter((kc) => typeof kc === 'string') - // we first replace all '+' with '\n' which we will use to split the keys on - // then we replace '\n\n' with '\n+', this way we can also support the combination 'key++' - // in the end we simply split on '\n' to get the key array + /* + * we first replace all '+' with '\n' which we will use to split the keys on + * then we replace '\n\n' with '\n+', this way we can also support the combination 'key++' + * in the end we simply split on '\n' to get the key array + */ .map((kc) => kc.replace('+', '\n').replace('\n\n', '\n+').split('\n')); const keysFlat = keys.reduce((res: Keys, item) => res.concat(...item), []); @@ -133,12 +157,16 @@ export function useKeyPress( function isMatchingKey(keyCodes: Array, pressedKeys: PressedKeys, isUp: boolean): boolean { return ( keyCodes - // we only want to compare same sizes of keyCode definitions - // and pressed keys. When the user specified 'Meta' as a key somewhere - // this would also be truthy without this filter when user presses 'Meta' + 'r' + /* + * we only want to compare same sizes of keyCode definitions + * and pressed keys. When the user specified 'Meta' as a key somewhere + * this would also be truthy without this filter when user presses 'Meta' + 'r' + */ .filter((keys) => isUp || keys.length === pressedKeys.size) - // since we want to support multiple possibilities only one of the - // combinations need to be part of the pressed keys + /* + * since we want to support multiple possibilities only one of the + * combinations need to be part of the pressed keys + */ .some((keys) => keys.every((k) => pressedKeys.has(k))) ); } diff --git a/packages/react/src/hooks/useMoveSelectedNodes.ts b/packages/react/src/hooks/useMoveSelectedNodes.ts index 52503c04..0b2dacc9 100644 --- a/packages/react/src/hooks/useMoveSelectedNodes.ts +++ b/packages/react/src/hooks/useMoveSelectedNodes.ts @@ -22,8 +22,10 @@ export function useMoveSelectedNodes() { const nodeUpdates = new Map(); const isSelected = selectedAndDraggable(nodesDraggable); - // by default a node moves 5px on each key press - // if snap grid is enabled, we use that for the velocity + /* + * by default a node moves 5px on each key press + * if snap grid is enabled, we use that for the velocity + */ const xVelo = snapToGrid ? snapGrid[0] : 5; const yVelo = snapToGrid ? snapGrid[1] : 5; diff --git a/packages/react/src/hooks/useNodeConnections.ts b/packages/react/src/hooks/useNodeConnections.ts index c83a7366..60ba894c 100644 --- a/packages/react/src/hooks/useNodeConnections.ts +++ b/packages/react/src/hooks/useNodeConnections.ts @@ -22,7 +22,7 @@ type UseNodeConnectionsParams = { }; /** - * Hook to retrieve all edges connected to a node. Can be filtered by handle type and id. + * This hook returns an array of connections on a specific node, handle type ('source', 'target') or handle ID. * * @public * @param param.id - node id - optional if called inside a custom node @@ -31,6 +31,22 @@ type UseNodeConnectionsParams = { * @param param.onConnect - gets called when a connection is established * @param param.onDisconnect - gets called when a connection is removed * @returns an array with connections + * + * @example + * ```jsx + *import { useNodeConnections } from '@xyflow/react'; + * + *export default function () { + * const connections = useNodeConnections({ + * type: 'target', + * handleId: 'my-handle', + * }); + * + * return ( + *
There are currently {connections.length} incoming connections!
+ * ); + *} + *``` */ export function useNodeConnections({ id, diff --git a/packages/react/src/hooks/useNodes.ts b/packages/react/src/hooks/useNodes.ts index 5e558e90..c64f7fb1 100644 --- a/packages/react/src/hooks/useNodes.ts +++ b/packages/react/src/hooks/useNodes.ts @@ -6,10 +6,23 @@ import type { Node, ReactFlowState } from '../types'; const nodesSelector = (state: ReactFlowState) => state.nodes; /** - * Hook for getting the current nodes from the store. + * This hook returns an array of the current nodes. Components that use this hook + *will re-render **whenever any node changes**, including when a node is selected + *or moved. * * @public * @returns An array of nodes + * + * @example + * ```jsx + *import { useNodes } from '@xyflow/react'; + * + *export default function() { + * const nodes = useNodes(); + * + * return
There are currently {nodes.length} nodes!
; + *} + *``` */ export function useNodes(): NodeType[] { const nodes = useStore(nodesSelector, shallow) as NodeType[]; diff --git a/packages/react/src/hooks/useNodesData.ts b/packages/react/src/hooks/useNodesData.ts index 7472cbf7..1d2aa37e 100644 --- a/packages/react/src/hooks/useNodesData.ts +++ b/packages/react/src/hooks/useNodesData.ts @@ -5,12 +5,24 @@ import { useStore } from '../hooks/useStore'; import type { Node } from '../types'; /** - * Hook for receiving data of one or multiple nodes + * This hook lets you subscribe to changes of a specific nodes `data` object. * * @public * @param nodeId - The id (or ids) of the node to get the data from - * @param guard - Optional guard function to narrow down the node type * @returns An object (or array of object) with {id, type, data} representing each node + * + * @example + * + *```jsx + *import { useNodesData } from '@xyflow/react'; + * + *export default function() { + * const nodeData = useNodesData('nodeId-1'); + * const nodesData = useNodesData(['nodeId-1', 'nodeId-2']); + * + * return null; + *} + *``` */ export function useNodesData( nodeId: string diff --git a/packages/react/src/hooks/useNodesEdgesState.ts b/packages/react/src/hooks/useNodesEdgesState.ts index fae87c02..b9722d80 100644 --- a/packages/react/src/hooks/useNodesEdgesState.ts +++ b/packages/react/src/hooks/useNodesEdgesState.ts @@ -4,11 +4,41 @@ import { applyNodeChanges, applyEdgeChanges } from '../utils/changes'; import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; /** - * Hook for managing the state of nodes - should only be used for prototyping / simple use cases. + * This hook makes it easy to prototype a controlled flow where you manage the + *state of nodes and edges outside the `ReactFlowInstance`. You can think of it + *like React's `useState` hook with an additional helper callback. * * @public * @param initialNodes * @returns an array [nodes, setNodes, onNodesChange] + * @example + * + *```tsx + *import { ReactFlow, useNodesState, useEdgesState } from '@xyflow/react'; + * + *const initialNodes = []; + *const initialEdges = []; + * + *export default function () { + * const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); + * const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); + * + * return ( + * + * ); + *} + *``` + * + *@remarks This hook was created to make prototyping easier and our documentation + *examples clearer. Although it is OK to use this hook in production, in + *practice you may want to use a more sophisticated state management solution + *like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. + * */ export function useNodesState( initialNodes: NodeType[] @@ -23,11 +53,41 @@ export function useNodesState( } /** - * Hook for managing the state of edges - should only be used for prototyping / simple use cases. + * This hook makes it easy to prototype a controlled flow where you manage the + *state of nodes and edges outside the `ReactFlowInstance`. You can think of it + *like React's `useState` hook with an additional helper callback. * * @public * @param initialEdges * @returns an array [edges, setEdges, onEdgesChange] + * @example + * + *```tsx + *import { ReactFlow, useNodesState, useEdgesState } from '@xyflow/react'; + * + *const initialNodes = []; + *const initialEdges = []; + * + *export default function () { + * const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); + * const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); + * + * return ( + * + * ); + *} + *``` + * + * @remarks This hook was created to make prototyping easier and our documentation + *examples clearer. Although it is OK to use this hook in production, in + *practice you may want to use a more sophisticated state management solution + *like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. + * */ export function useEdgesState( initialEdges: EdgeType[] diff --git a/packages/react/src/hooks/useNodesInitialized.ts b/packages/react/src/hooks/useNodesInitialized.ts index 98bfa6b7..38f15a60 100644 --- a/packages/react/src/hooks/useNodesInitialized.ts +++ b/packages/react/src/hooks/useNodesInitialized.ts @@ -1,6 +1,7 @@ +import { nodeHasDimensions } from '@xyflow/system'; + import { useStore } from './useStore'; import type { ReactFlowState } from '../types'; -import { nodeHasDimensions } from '@xyflow/system'; export type UseNodesInitializedOptions = { includeHiddenNodes?: boolean; @@ -22,18 +23,44 @@ const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) => return true; }; -const defaultOptions = { - includeHiddenNodes: false, -}; - /** - * Hook which returns true when all nodes are initialized. + * This hook tells you whether all the nodes in a flow have been measured and given + *a width and height. When you add a node to the flow, this hook will return + *`false` and then `true` again once the node has been measured. * * @public * @param options.includeHiddenNodes - defaults to false * @returns boolean indicating whether all nodes are initialized + * + * @example + * ```jsx + *import { useReactFlow, useNodesInitialized } from '@xyflow/react'; + *import { useEffect, useState } from 'react'; + * + *const options = { + * includeHiddenNodes: false, + *}; + * + *export default function useLayout() { + * const { getNodes } = useReactFlow(); + * const nodesInitialized = useNodesInitialized(options); + * const [layoutedNodes, setLayoutedNodes] = useState(getNodes()); + * + * useEffect(() => { + * if (nodesInitialized) { + * setLayoutedNodes(yourLayoutingFunction(getNodes())); + * } + * }, [nodesInitialized]); + * + * return layoutedNodes; + *} + *``` */ -export function useNodesInitialized(options: UseNodesInitializedOptions = defaultOptions): boolean { +export function useNodesInitialized( + options: UseNodesInitializedOptions = { + includeHiddenNodes: false, + } +): boolean { const initialized = useStore(selector(options)); return initialized; diff --git a/packages/react/src/hooks/useOnSelectionChange.ts b/packages/react/src/hooks/useOnSelectionChange.ts index 8e08191b..65cad6fd 100644 --- a/packages/react/src/hooks/useOnSelectionChange.ts +++ b/packages/react/src/hooks/useOnSelectionChange.ts @@ -8,10 +8,42 @@ export type UseOnSelectionChangeOptions = { }; /** - * Hook for registering an onSelectionChange handler. + * This hook lets you listen for changes to both node and edge selection. As the + *name implies, the callback you provide will be called whenever the selection of + *_either_ nodes or edges changes. * * @public * @param params.onChange - The handler to register + * + * @example + * ```jsx + *import { useState } from 'react'; + *import { ReactFlow, useOnSelectionChange } from '@xyflow/react'; + * + *function SelectionDisplay() { + * const [selectedNodes, setSelectedNodes] = useState([]); + * const [selectedEdges, setSelectedEdges] = useState([]); + * + * // the passed handler has to be memoized, otherwise the hook will not work correctly + * const onChange = useCallback(({ nodes, edges }) => { + * setSelectedNodes(nodes.map((node) => node.id)); + * setSelectedEdges(edges.map((edge) => edge.id)); + * }, []); + * + * useOnSelectionChange({ + * onChange, + * }); + * + * return ( + *
+ *

Selected nodes: {selectedNodes.join(', ')}

+ *

Selected edges: {selectedEdges.join(', ')}

+ *
+ * ); + *} + *``` + * + * @remarks You need to memoize the passed `onChange` handler, otherwise the hook will not work correctly. */ export function useOnSelectionChange({ onChange }: UseOnSelectionChangeOptions) { const store = useStoreApi(); diff --git a/packages/react/src/hooks/useOnViewportChange.ts b/packages/react/src/hooks/useOnViewportChange.ts index 61e4d64f..c82eb344 100644 --- a/packages/react/src/hooks/useOnViewportChange.ts +++ b/packages/react/src/hooks/useOnViewportChange.ts @@ -10,12 +10,30 @@ export type UseOnViewportChangeOptions = { }; /** - * Hook for registering an onViewportChange handler. + * The `useOnViewportChange` hook lets you listen for changes to the viewport such + *as panning and zooming. You can provide a callback for each phase of a viewport + *change: `onStart`, `onChange`, and `onEnd`. * * @public * @param params.onStart - gets called when the viewport starts changing * @param params.onChange - gets called when the viewport changes * @param params.onEnd - gets called when the viewport stops changing + * + * @example + * ```jsx + *import { useCallback } from 'react'; + *import { useOnViewportChange } from '@xyflow/react'; + * + *function ViewportChangeLogger() { + * useOnViewportChange({ + * onStart: (viewport: Viewport) => console.log('start', viewport), + * onChange: (viewport: Viewport) => console.log('change', viewport), + * onEnd: (viewport: Viewport) => console.log('end', viewport), + * }); + * + * return null; + *} + *``` */ export function useOnViewportChange({ onStart, onChange, onEnd }: UseOnViewportChangeOptions) { const store = useStoreApi(); diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index 3d857cfa..57b2e001 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -20,10 +20,33 @@ import type { ReactFlowInstance, Node, Edge, InternalNode, ReactFlowState, Gener const selector = (s: ReactFlowState) => !!s.panZoom; /** - * Hook for accessing the ReactFlow instance. + * This hook returns a ReactFlowInstance that can be used to update nodes and edges, manipulate the viewport, or query the current state of the flow. * * @public * @returns ReactFlowInstance + * + * @example + * ```jsx + *import { useCallback, useState } from 'react'; + *import { useReactFlow } from '@xyflow/react'; + * + *export function NodeCounter() { + * const reactFlow = useReactFlow(); + * const [count, setCount] = useState(0); + * const countNodes = useCallback(() => { + * setCount(reactFlow.getNodes().length); + * // you need to pass it as a dependency if you are using it with useEffect or useCallback + * // because at the first render, it's not initialized yet and some functions might not work. + * }, [reactFlow]); + * + * return ( + *
+ * + *

There are {count} nodes in the flow.

+ *
+ * ); + *} + *``` */ export function useReactFlow(): ReactFlowInstance< NodeType, diff --git a/packages/react/src/hooks/useStore.ts b/packages/react/src/hooks/useStore.ts index 88c1abad..e34e2c36 100644 --- a/packages/react/src/hooks/useStore.ts +++ b/packages/react/src/hooks/useStore.ts @@ -9,7 +9,9 @@ import type { Edge, Node, ReactFlowState } from '../types'; const zustandErrorMessage = errorMessages['error001'](); /** - * Hook for accessing the internal store. Should only be used in rare cases. + * This hook can be used to subscribe to internal state changes of the React Flow + *component. The `useStore` hook is re-exported from the [Zustand](https://github.com/pmndrs/zustand) + *state management library, so you should check out their docs for more details. * * @public * @param selector @@ -17,8 +19,13 @@ const zustandErrorMessage = errorMessages['error001'](); * @returns The selected state slice * * @example - * const nodes = useStore((state: ReactFlowState) => state.nodes); + * ```ts + * const nodes = useStore((state) => state.nodes); + * ``` * + * @remarks This hook should only be used if there is no other way to access the internal + *state. For many of the common use cases, there are dedicated hooks available + *such as {@link useReactFlow}, {@link useViewport}, etc. */ function useStore( selector: (state: ReactFlowState) => StateSlice, @@ -33,6 +40,20 @@ function useStore( return useZustandStore(store, selector, equalityFn); } +/** + * In some cases, you might need to access the store directly. This hook returns the store object which can be used on demand to access the state or dispatch actions. + * + * @returns The store object + * + * @example + * ```ts + * const store = useStoreApi(); + * ``` + * + * @remarks This hook should only be used if there is no other way to access the internal + *state. For many of the common use cases, there are dedicated hooks available + *such as {@link useReactFlow}, {@link useViewport}, etc. + */ function useStoreApi() { const store = useContext(StoreContext) as UseBoundStoreWithEqualityFn< StoreApi> diff --git a/packages/react/src/hooks/useUpdateNodeInternals.ts b/packages/react/src/hooks/useUpdateNodeInternals.ts index 6486afd8..4463ed2a 100644 --- a/packages/react/src/hooks/useUpdateNodeInternals.ts +++ b/packages/react/src/hooks/useUpdateNodeInternals.ts @@ -4,10 +4,48 @@ import type { UpdateNodeInternals, InternalNodeUpdate } from '@xyflow/system'; import { useStoreApi } from '../hooks/useStore'; /** - * Hook for updating node internals. + * When you programmatically add or remove handles to a node or update a node's + *handle position, you need to let React Flow know about it using this hook. This + *will update the internal dimensions of the node and properly reposition handles + *on the canvas if necessary. * * @public * @returns function for updating node internals + * + * @example + * ```jsx + *import { useCallback, useState } from 'react'; + *import { Handle, useUpdateNodeInternals } from '@xyflow/react'; + * + *export default function RandomHandleNode({ id }) { + * const updateNodeInternals = useUpdateNodeInternals(); + * const [handleCount, setHandleCount] = useState(0); + * const randomizeHandleCount = useCallback(() => { + * setHandleCount(Math.floor(Math.random() * 10)); + * updateNodeInternals(id); + * }, [id, updateNodeInternals]); + * + * return ( + * <> + * {Array.from({ length: handleCount }).map((_, index) => ( + * + * ))} + * + *
+ * + *

There are {handleCount} handles on this node.

+ *
+ * + * ); + *} + *``` + * @remarks This hook can only be used in a component that is a child of a + *{@link ReactFlowProvider} or a {@link ReactFlow} component. */ export function useUpdateNodeInternals(): UpdateNodeInternals { const store = useStoreApi(); diff --git a/packages/react/src/hooks/useViewport.ts b/packages/react/src/hooks/useViewport.ts index 0b9758c1..a892e5a8 100644 --- a/packages/react/src/hooks/useViewport.ts +++ b/packages/react/src/hooks/useViewport.ts @@ -11,10 +11,33 @@ const viewportSelector = (state: ReactFlowState) => ({ }); /** - * Hook for getting the current viewport from the store. + * The `useViewport` hook is a convenient way to read the current state of the + *{@link Viewport} in a component. Components that use this hook + *will re-render **whenever the viewport changes**. * * @public * @returns The current viewport + * + * @example + * + *```jsx + *import { useViewport } from '@xyflow/react'; + * + *export default function ViewportDisplay() { + * const { x, y, zoom } = useViewport(); + * + * return ( + *
+ *

+ * The viewport is currently at ({x}, {y}) and zoomed to {zoom}. + *

+ *
+ * ); + *} + *``` + * + * @remarks This hook can only be used in a component that is a child of a + *{@link ReactFlowProvider} or a {@link ReactFlow} component. */ export function useViewport(): Viewport { const viewport = useStore(viewportSelector, shallow); diff --git a/packages/react/src/hooks/useVisibleNodeIds.ts b/packages/react/src/hooks/useVisibleNodeIds.ts index e8d14c8e..a0006940 100644 --- a/packages/react/src/hooks/useVisibleNodeIds.ts +++ b/packages/react/src/hooks/useVisibleNodeIds.ts @@ -8,8 +8,8 @@ import type { Node, ReactFlowState } from '../types'; const selector = (onlyRenderVisible: boolean) => (s: ReactFlowState) => { return onlyRenderVisible ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map( - (node) => node.id - ) + (node) => node.id + ) : Array.from(s.nodeLookup.keys()); }; diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 2466baa5..0f07d0f1 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -47,12 +47,14 @@ const createStore = ({ ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), setNodes: (nodes: Node[]) => { const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get(); - // setNodes() is called exclusively in response to user actions: - // - either when the `` prop is updated in the controlled ReactFlow setup, - // - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup. - // - // When this happens, we take the note objects passed by the user and extend them with fields - // relevant for internal React Flow operations. + /* + * setNodes() is called exclusively in response to user actions: + * - either when the `` prop is updated in the controlled ReactFlow setup, + * - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup. + * + * When this happens, we take the note objects passed by the user and extend them with fields + * relevant for internal React Flow operations. + */ adoptUserNodes(nodes, nodeLookup, parentLookup, { nodeOrigin, nodeExtent, @@ -81,9 +83,11 @@ const createStore = ({ set({ hasDefaultEdges: true }); } }, - // 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. + /* + * 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, params = { triggerFitView: true }) => { const { triggerNodeChanges, @@ -125,11 +129,13 @@ const createStore = ({ }); } - // 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. + /* + * 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 @@ -155,9 +161,9 @@ const createStore = ({ type: 'position', position: expandParent ? { - x: Math.max(0, dragItem.position.x), - y: Math.max(0, dragItem.position.y), - } + x: Math.max(0, dragItem.position.x), + y: Math.max(0, dragItem.position.y), + } : dragItem.position, dragging, }; @@ -248,8 +254,10 @@ const createStore = ({ const nodeChanges = nodesToUnselect.map((n) => { const internalNode = nodeLookup.get(n.id); if (internalNode) { - // we need to unselect the internal node that was selected previously before we - // send the change to the user to prevent it to be selected while dragging the new node + /* + * we need to unselect the internal node that was selected previously before we + * send the change to the user to prevent it to be selected while dragging the new node + */ internalNode.selected = false; } @@ -342,8 +350,10 @@ const createStore = ({ options ); }, - // we can't call an asnychronous function in updateNodeInternals - // for that we created this sync version of fitView + /* + * we can't call an asnychronous function in updateNodeInternals + * for that we created this sync version of fitView + */ fitViewSync: (options?: FitViewOptions): boolean => { const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get(); diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index d04875d1..2f318174 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -52,7 +52,8 @@ import type { */ export interface ReactFlowProps extends Omit, 'onError'> { - /** An array of nodes to render in a controlled flow. + /** + * An array of nodes to render in a controlled flow. * @example * const nodes = [ * { @@ -64,7 +65,8 @@ export interface ReactFlowProps; onReconnectStart?: (event: ReactMouseEvent, edge: EdgeType, handleType: HandleType) => void; onReconnectEnd?: (event: MouseEvent | TouchEvent, edge: EdgeType, handleType: HandleType) => void; - /** This event handler is called when a Node is updated + /** + * This event handler is called when a Node is updated * @example // Use NodesState hook to create edges and get onNodesChange handler * import ReactFlow, { useNodesState } from '@xyflow/react'; * const [edges, setNodes, onNodesChange] = useNodesState(initialNodes); @@ -149,7 +153,8 @@ export interface ReactFlowProps) */ onNodesChange?: OnNodesChange; - /** This event handler is called when a Edge is updated + /** + * This event handler is called when a Edge is updated * @example // Use EdgesState hook to create edges and get onEdgesChange handler * import ReactFlow, { useEdgesState } from '@xyflow/react'; * const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); @@ -181,7 +186,8 @@ export interface ReactFlowProps void; onSelectionEnd?: (event: ReactMouseEvent) => void; onSelectionContextMenu?: (event: ReactMouseEvent, nodes: NodeType[]) => void; - /** When a connection line is completed and two nodes are connected by the user, this event fires with the new connection. + /** + * 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 @@ -223,17 +229,20 @@ export interface ReactFlowProps void; /** This event handler gets called when mouse leaves the pane */ onPaneMouseLeave?: (event: ReactMouseEvent) => void; - /** Distance that the mouse can move between mousedown/up that will trigger a click + /** + * Distance that the mouse can move between mousedown/up that will trigger a click * @default 0 */ paneClickDistance?: number; - /** Distance that the mouse can move between mousedown/up that will trigger a click + /** + * Distance that the mouse can move between mousedown/up that will trigger a click * @default 0 */ nodeClickDistance?: number; /** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */ onBeforeDelete?: OnBeforeDelete; - /** Custom node types to be available in a flow. + /** + * Custom node types to be available in a flow. * * React Flow matches a node's type to a component in the nodeTypes object. * @example @@ -242,7 +251,8 @@ export interface ReactFlowProps void; - /** By default the viewport extends infinitely. You can use this prop to set a boundary. + /** + * 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. * @example [[-1000, -10000], [1000, 1000]] */ translateExtent?: CoordinateExtent; - /** Disabling this prop will allow the user to scroll the page even when their pointer is over the flow. + /** + * Disabling this prop will allow the user to scroll the page even when their pointer is over the flow. * @default true */ preventScrolling?: boolean; - /** By default nodes can be placed on an infinite flow. You can use this prop to set a boundary. + /** + * 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; - /** Color of edge markers + /** + * Color of edge markers * @example "#b1b1b7" */ defaultMarkerColor?: string; @@ -402,17 +439,20 @@ export interface ReactFlowProps true */ isValidConnection?: IsValidConnection; - /** With a threshold greater than zero you can control the distinction between node drag and click events. + /** + * With a threshold greater than zero you can control the distinction between node drag and click events. * * If threshold equals 1, you need to drag the node 1 pixel before a drag event is fired. * @default 1 @@ -510,12 +563,14 @@ export interface ReactFlowProps(); const addItemChanges: any[] = []; @@ -26,15 +30,19 @@ function applyChanges(changes: any[], elements: any[]): any[] { 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 - // the same element, it's going to be removed anyway! + /* + * For a 'remove' change we can safely ignore any other changes queued for + * the same element, it's going to be removed anyway! + */ changesMap.set(change.id, [change]); } else { const elementChanges = changesMap.get(change.id); if (elementChanges) { - // If we have some changes queued already, we can do a mutable update of - // that array and save ourselves some copying. + /* + * If we have some changes queued already, we can do a mutable update of + * that array and save ourselves some copying. + */ elementChanges.push(change); } else { changesMap.set(change.id, [change]); @@ -45,8 +53,10 @@ function applyChanges(changes: any[], elements: any[]): any[] { for (const element of elements) { const changes = changesMap.get(element.id); - // When there are no changes for an element we can just push it unmodified, - // no need to copy it. + /* + * When there are no changes for an element we can just push it unmodified, + * no need to copy it. + */ if (!changes) { updatedElements.push(element); continue; @@ -62,9 +72,11 @@ function applyChanges(changes: any[], elements: any[]): any[] { continue; } - // For other types of changes, we want to start with a shallow copy of the - // object so React knows this element has changed. Sequential changes will - /// each _mutate_ this object, so there's only ever one copy. + /** + * For other types of changes, we want to start with a shallow copy of the + * object so React knows this element has changed. Sequential changes will + * each _mutate_ this object, so there's only ever one copy. + */ const updatedElement = { ...element }; for (const change of changes) { @@ -74,8 +86,10 @@ 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 + /* + * 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) { @@ -134,21 +148,21 @@ function applyChange(change: any, element: any): any { * Drop in function that applies node changes to an array of nodes. * @public * @remarks Various events on the component can produce an {@link NodeChange} that describes how to update the edges of your flow in some way. - If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. + *If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. * @param changes - Array of changes to apply * @param nodes - Array of nodes to apply the changes to * @returns Array of updated nodes * @example * const onNodesChange = useCallback( - (changes) => { - setNodes((oldNodes) => applyNodeChanges(changes, oldNodes)); - }, - [setNodes], - ); - - return ( - - ); + * (changes) => { + * setNodes((oldNodes) => applyNodeChanges(changes, oldNodes)); + * }, + * [setNodes], + * ); + * + * return ( + * + * ); */ export function applyNodeChanges( changes: NodeChange[], @@ -161,21 +175,21 @@ export function applyNodeChanges( * Drop in function that applies edge changes to an array of edges. * @public * @remarks Various events on the component can produce an {@link EdgeChange} that describes how to update the edges of your flow in some way. - If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. + *If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. * @param changes - Array of changes to apply * @param edges - Array of edge to apply the changes to * @returns Array of updated edges * @example * const onEdgesChange = useCallback( - (changes) => { - setEdges((oldEdges) => applyEdgeChanges(changes, oldEdges)); - }, - [setEdges], - ); - - return ( - - ); + * (changes) => { + * setEdges((oldEdges) => applyEdgeChanges(changes, oldEdges)); + * }, + * [setEdges], + * ); + * + * return ( + * + * ); */ export function applyEdgeChanges( changes: EdgeChange[], @@ -205,9 +219,11 @@ export function getSelectionChanges( // we don't want to set all items to selected=false on the first selection if (!(item.selected === undefined && !willBeSelected) && item.selected !== willBeSelected) { if (mutateItem) { - // this hack is needed for nodes. When the user dragged a node, it's selected. - // When another node gets dragged, we need to deselect the previous one, - // in order to have only one selected node at a time - the onNodesChange callback comes too late here :/ + /* + * this hack is needed for nodes. When the user dragged a node, it's selected. + * When another node gets dragged, we need to deselect the previous one, + * in order to have only one selected node at a time - the onNodesChange callback comes too late here :/ + */ item.selected = willBeSelected; } changes.push(createSelectionChange(item.id, willBeSelected)); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22541966..6ae9a41c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,6 +428,9 @@ importers: tooling/eslint-config: devDependencies: + '@stylistic/eslint-plugin': + specifier: ^3.1.0 + version: 3.1.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/eslint-plugin': specifier: ^8.23.0 version: 8.23.0(@typescript-eslint/parser@8.23.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) @@ -1706,6 +1709,12 @@ packages: resolution: {integrity: sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==} engines: {node: '>=18'} + '@stylistic/eslint-plugin@3.1.0': + resolution: {integrity: sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + '@svelte-put/shortcut@3.1.1': resolution: {integrity: sha512-2L5EYTZXiaKvbEelVkg5znxqvfZGZai3m97+cAiUBhLZwXnGtviTDpHxOoZBsqz41szlfRMcamW/8o0+fbW3ZQ==} peerDependencies: @@ -2217,6 +2226,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -3290,6 +3304,10 @@ packages: esm-env@1.0.0: resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4776,6 +4794,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -7959,6 +7981,18 @@ snapshots: '@sindresorhus/merge-streams@1.0.0': {} + '@stylistic/eslint-plugin@3.1.0(eslint@8.57.0)(typescript@5.4.5)': + dependencies: + '@typescript-eslint/utils': 8.23.0(eslint@8.57.0)(typescript@5.4.5) + eslint: 8.57.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + estraverse: 5.3.0 + picomatch: 4.0.2 + transitivePeerDependencies: + - supports-color + - typescript + '@svelte-put/shortcut@3.1.1(svelte@4.2.12)': dependencies: svelte: 4.2.12 @@ -8613,12 +8647,18 @@ snapshots: dependencies: acorn: 8.10.0 + acorn-jsx@5.3.2(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn@8.10.0: {} acorn@8.11.2: {} acorn@8.11.3: {} + acorn@8.14.0: {} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -10257,6 +10297,12 @@ snapshots: esm-env@1.0.0: {} + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + espree@9.6.1: dependencies: acorn: 8.10.0 @@ -11961,6 +12007,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.2: {} + pify@2.3.0: {} pify@4.0.1: {} diff --git a/tooling/eslint-config/package.json b/tooling/eslint-config/package.json index 00da90da..2c664276 100644 --- a/tooling/eslint-config/package.json +++ b/tooling/eslint-config/package.json @@ -5,11 +5,12 @@ "license": "MIT", "main": "src/index.js", "devDependencies": { - "eslint-config-prettier": "^10.0.1", - "eslint-config-turbo": "^2.4.0", - "eslint-plugin-react": "^7.37.4", + "@stylistic/eslint-plugin": "^3.1.0", "@typescript-eslint/eslint-plugin": "^8.23.0", "@typescript-eslint/parser": "^8.23.0", - "eslint-plugin-prettier": "^4.2.1" + "eslint-config-prettier": "^10.0.1", + "eslint-config-turbo": "^2.4.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-react": "^7.37.4" } } diff --git a/tooling/eslint-config/src/index.js b/tooling/eslint-config/src/index.js index f2ce34a0..7bd69b5a 100644 --- a/tooling/eslint-config/src/index.js +++ b/tooling/eslint-config/src/index.js @@ -13,7 +13,7 @@ module.exports = { 'turbo', 'prettier', ], - plugins: ['react', '@typescript-eslint'], + plugins: ['react', '@typescript-eslint', '@stylistic'], parserOptions: { ecmaFeatures: { jsx: true, @@ -28,5 +28,7 @@ module.exports = { }, rules: { '@typescript-eslint/no-non-null-assertion': 'off', + '@stylistic/indent': ['error', 2], + '@stylistic/multiline-comment-style': ['error', 'starred-block'], }, }; From 6c937546e49cb876886e6a633075516600a1d449 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 14:19:33 +0100 Subject: [PATCH 009/157] chore(comps): tsdoc update --- .../Controls/ControlButton.tsx | 23 +++++++++++ .../Controls/Controls.tsx | 22 ++++++++++ .../additional-components/MiniMap/MiniMap.tsx | 20 +++++++++ .../NodeResizer/NodeResizeControl.tsx | 5 +++ .../NodeResizer/NodeResizer.tsx | 24 +++++++++++ .../NodeToolbar/NodeToolbar.tsx | 36 ++++++++++++++++ .../components/EdgeLabelRenderer/index.tsx | 41 +++++++++++++++++++ .../react/src/components/Edges/BaseEdge.tsx | 27 ++++++++++++ .../react/src/components/Edges/EdgeText.tsx | 26 ++++++++++++ .../react/src/components/Handle/index.tsx | 24 ++++++++++- packages/react/src/components/Panel/index.tsx | 30 ++++++++++++-- .../src/components/ViewportPortal/index.tsx | 24 +++++++++++ 12 files changed, 298 insertions(+), 4 deletions(-) diff --git a/packages/react/src/additional-components/Controls/ControlButton.tsx b/packages/react/src/additional-components/Controls/ControlButton.tsx index 744f46d4..12c58663 100644 --- a/packages/react/src/additional-components/Controls/ControlButton.tsx +++ b/packages/react/src/additional-components/Controls/ControlButton.tsx @@ -2,6 +2,29 @@ import cc from 'classcat'; import type { ControlButtonProps } from './types'; +/** + * You can add buttons to the control panel by using the `` component + *and pass it as a child to the [``](/api-reference/components/controls) component. + * + * @public + * @example + *```jsx + *import { MagicWand } from '@radix-ui/react-icons' + *import { ReactFlow, Controls, ControlButton } from '@xyflow/react' + * + *export default function Flow() { + * return ( + * + * + * alert('Something magical just happened. ✨')}> + * + * + * + * + * ) + *} + *``` + */ export function ControlButton({ children, className, ...rest }: ControlButtonProps) { return ( + * + * + * + * + *
+ * {data.label} + *
+ * + * + * + * + * ); + *}; + * + *export default memo(CustomNode); + *``` + * @remarks By default, the toolbar is only visible when a node is selected. If multiple + *nodes are selected it will not be visible to prevent overlapping toolbars or + *clutter. You can override this behavior by setting the `isVisible` prop to + *`true`. + */ export function NodeToolbar({ nodeId, children, diff --git a/packages/react/src/components/EdgeLabelRenderer/index.tsx b/packages/react/src/components/EdgeLabelRenderer/index.tsx index c66b70ae..b3aa1a91 100644 --- a/packages/react/src/components/EdgeLabelRenderer/index.tsx +++ b/packages/react/src/components/EdgeLabelRenderer/index.tsx @@ -6,6 +6,47 @@ import type { ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__edgelabel-renderer'); +/** + * Edges are SVG-based. If you want to render more complex labels you can use the + *`` component to access a div based renderer. This component + *is a portal that renders the label in a `
` that is positioned on top of + *the edges. You can see an example usage of the component in the [edge label renderer](/examples/edges/edge-label-renderer) + *example. + * @public + * + * @example + *```jsx + *import React from 'react'; + *import { getBezierPath, EdgeLabelRenderer, BaseEdge } from '@xyflow/react'; + * + *export function CustomEdge({ id, data, ...props }) { + * const [edgePath, labelX, labelY] = getBezierPath(props); + * + * return ( + * <> + * + * + *
+ * {data.label} + *
+ *
+ * + * ); + *}; + *``` + * + *@remarks The `` has no pointer events by default. If you want to + *add mouse interactions you need to set the style `pointerEvents: all` and add + *the `nopan` class on the label or the element you want to interact with. + */ export function EdgeLabelRenderer({ children }: { children: ReactNode }) { const edgeLabelRenderer = useStore(selector); diff --git a/packages/react/src/components/Edges/BaseEdge.tsx b/packages/react/src/components/Edges/BaseEdge.tsx index 3d951796..e19412f2 100644 --- a/packages/react/src/components/Edges/BaseEdge.tsx +++ b/packages/react/src/components/Edges/BaseEdge.tsx @@ -4,6 +4,33 @@ import cc from 'classcat'; import { EdgeText } from './EdgeText'; import type { BaseEdgeProps } from '../../types'; +/** + * The `` component gets used internally for all the edges. It can be + *used inside a custom edge and handles the invisible helper edge and the edge label + *for you. + * + * @public + * @example + * ```jsx + *import { BaseEdge } from '@xyflow/react'; + * + *export function CustomEdge({ sourceX, sourceY, targetX, targetY, ...props }) { + * const [edgePath] = getStraightPath({ + * sourceX, + * sourceY, + * targetX, + * targetY, + * }); + * + * return ; + *} + *``` + * + * @remarks If you want to use an edge marker with the [``](/api-reference/components/base-edge) component, + *you can pass the `markerStart` or `markerEnd` props passed to your custom edge + *through to the [``](/api-reference/components/base-edge) component. You can see all the props + *passed to a custom edge by looking at the [`EdgeProps`](/api-reference/types/edge-props) type. + */ export function BaseEdge({ path, labelX, diff --git a/packages/react/src/components/Edges/EdgeText.tsx b/packages/react/src/components/Edges/EdgeText.tsx index 2e3ad041..e2d162b0 100644 --- a/packages/react/src/components/Edges/EdgeText.tsx +++ b/packages/react/src/components/Edges/EdgeText.tsx @@ -73,4 +73,30 @@ function EdgeTextComponent({ EdgeTextComponent.displayName = 'EdgeText'; +/** + * You can use the `` component as a helper component to display text + *within your custom edges. + * + *@public + * + *@example + *```jsx + *import { EdgeText } from '@xyflow/react'; + * + *export function CustomEdgeLabel({ label }) { + * return ( + * + * ); + *} + *``` + */ export const EdgeText = memo(EdgeTextComponent); diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index 70e52dbe..07d18378 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -250,6 +250,28 @@ function HandleComponent( } /** - * The Handle component is a UI element that is used to connect nodes. + * The `` component is used in your [custom nodes](/learn/customization/custom-nodes) + *to define connection points. + * + *@public + * + *@example + * + *```jsx + *import { Handle, Position } from '@xyflow/react'; + * + *export function CustomNode({ data }) { + * return ( + * <> + *
+ * {data.label} + *
+ * + * + * + * + * ); + *}; + *``` */ export const Handle = memo(fixedForwardRef(HandleComponent)); diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index 63695928..1859b034 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -5,10 +5,34 @@ import type { PanelPosition } from '@xyflow/system'; import { useStore } from '../../hooks/useStore'; import type { ReactFlowState } from '../../types'; +/** + * The `` component helps you position content above the viewport. It is + *used internally by the [``](/api-reference/components/minimap) and [``](/api-reference/components/controls) + *components. + * + * @public + * + * @example + * ```jsx + *import { ReactFlow, Background, Panel } from '@xyflow/react'; + * + *export default function Flow() { + * return ( + * + * top-left + * top-center + * top-right + * bottom-left + * bottom-center + * bottom-right + * + * ); + *} + *``` + */ export type PanelProps = HTMLAttributes & { /** - * Set position of the panel - * @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' + * The position of the panel */ position?: PanelPosition; children: ReactNode; @@ -34,4 +58,4 @@ export const Panel = forwardRef( } ); -Panel.displayName = 'Panel' +Panel.displayName = 'Panel'; diff --git a/packages/react/src/components/ViewportPortal/index.tsx b/packages/react/src/components/ViewportPortal/index.tsx index c1b9b406..ea306935 100644 --- a/packages/react/src/components/ViewportPortal/index.tsx +++ b/packages/react/src/components/ViewportPortal/index.tsx @@ -6,6 +6,30 @@ import type { ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__viewport-portal'); +/** + * The `` component can be used to add components to the same viewport of the flow where nodes and edges are rendered. + *This is useful when you want to render your own components that are adhere to the same coordinate system as the nodes & edges and are also + *affected by zooming and panning + * @public + * @example + * + * ```jsx + *import React from 'react'; + *import { ViewportPortal } from '@xyflow/react'; + * + *export default function () { + * return ( + * + *
+ * This div is positioned at [100, 100] on the flow. + *
+ *
+ * ); + *} + *``` + */ export function ViewportPortal({ children }: { children: ReactNode }) { const viewPortalDiv = useStore(selector); From fb63462be3be780c83c24f472546b47ff24630a6 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 15:18:41 +0100 Subject: [PATCH 010/157] chore(utils): tsdoc update --- .../examples/UseOnSelectionChange/index.tsx | 1 - .../src/components/Edges/SimpleBezierEdge.tsx | 5 + packages/react/src/utils/changes.ts | 23 ++++- packages/react/src/utils/general.ts | 26 ++++- packages/system/package.json | 2 +- packages/system/src/types/edges.ts | 12 ++- packages/system/src/types/handles.ts | 12 ++- packages/system/src/types/nodes.ts | 21 ++-- packages/system/src/utils/dom.ts | 8 +- .../system/src/utils/edges/bezier-edge.ts | 35 ++++--- packages/system/src/utils/edges/general.ts | 14 ++- .../system/src/utils/edges/smoothstep-edge.ts | 50 ++++++---- .../system/src/utils/edges/straight-edge.ts | 26 ++--- packages/system/src/utils/general.ts | 4 +- packages/system/src/utils/graph.ts | 95 +++++++++++++++++-- packages/system/src/utils/node-toolbar.ts | 6 +- packages/system/src/utils/store.ts | 14 ++- packages/system/src/xydrag/XYDrag.ts | 12 ++- packages/system/src/xydrag/utils.ts | 16 ++-- packages/system/src/xyhandle/XYHandle.ts | 18 ++-- packages/system/src/xyhandle/utils.ts | 6 +- packages/system/src/xypanzoom/XYPanZoom.ts | 38 ++++---- packages/system/src/xypanzoom/eventhandler.ts | 14 ++- packages/system/src/xyresizer/XYResizer.ts | 12 ++- 24 files changed, 336 insertions(+), 134 deletions(-) diff --git a/examples/react/src/examples/UseOnSelectionChange/index.tsx b/examples/react/src/examples/UseOnSelectionChange/index.tsx index b9795951..fdbe124a 100644 --- a/examples/react/src/examples/UseOnSelectionChange/index.tsx +++ b/examples/react/src/examples/UseOnSelectionChange/index.tsx @@ -10,7 +10,6 @@ import { useEdgesState, useOnSelectionChange, OnSelectionChangeParams, - OnSelectionChangeFunc, } from '@xyflow/react'; const initialNodes: Node[] = [ diff --git a/packages/react/src/components/Edges/SimpleBezierEdge.tsx b/packages/react/src/components/Edges/SimpleBezierEdge.tsx index b3378c48..102c163e 100644 --- a/packages/react/src/components/Edges/SimpleBezierEdge.tsx +++ b/packages/react/src/components/Edges/SimpleBezierEdge.tsx @@ -29,6 +29,11 @@ function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] return [x1, 0.5 * (y1 + y2)]; } +/** + * The `getSimpleBezierPath` util returns everything you need to render a simple +bezier edge between two nodes. + * @public + */ export function getSimpleBezierPath({ sourceX, sourceY, diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index eac8b9d3..ea0a9140 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -153,7 +153,14 @@ function applyChange(change: any, element: any): any { * @param nodes - Array of nodes to apply the changes to * @returns Array of updated nodes * @example - * const onNodesChange = useCallback( + *```tsx + *import { useState, useCallback } from 'react'; + *import { ReactFlow, applyNodeChanges, type Node, type Edge, type OnNodesChange } from '@xyflow/react'; + * + *export default function Flow() { + * const [nodes, setNodes] = useState([]); + * const [edges, setEdges] = useState([]); + * const onNodesChange: OnNodesChange = useCallback( * (changes) => { * setNodes((oldNodes) => applyNodeChanges(changes, oldNodes)); * }, @@ -161,8 +168,10 @@ function applyChange(change: any, element: any): any { * ); * * return ( - * + * * ); + *} + *``` */ export function applyNodeChanges( changes: NodeChange[], @@ -180,6 +189,14 @@ export function applyNodeChanges( * @param edges - Array of edge to apply the changes to * @returns Array of updated edges * @example + * + * ```tsx + *import { useState, useCallback } from 'react'; + *import { ReactFlow, applyEdgeChanges } from '@xyflow/react'; + * + *export default function Flow() { + * const [nodes, setNodes] = useState([]); + * const [edges, setEdges] = useState([]); * const onEdgesChange = useCallback( * (changes) => { * setEdges((oldEdges) => applyEdgeChanges(changes, oldEdges)); @@ -190,6 +207,8 @@ export function applyNodeChanges( * return ( * * ); + *} + *``` */ export function applyEdgeChanges( changes: EdgeChange[], diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index 04608f74..6ac2e3c5 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -4,21 +4,43 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '../types'; /** - * Test whether an object is useable as a Node + * Test whether an object is useable as an [`Node`](/api-reference/types/node). In TypeScript + *this is a type guard that will narrow the type of whatever you pass in to + *[`Node`](/api-reference/types/node) if it returns `true`. * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true * @param element - The element to test * @returns A boolean indicating whether the element is an Node + * + * @example + * ```js + *import { isNode } from '@xyflow/react'; + * + *if (isNode(node)) { + * // .. + *} + *``` */ export const isNode = (element: unknown): element is NodeType => isNodeBase(element); /** - * Test whether an object is useable as an Edge + * Test whether an object is useable as an [`Edge`](/api-reference/types/edge). In TypeScript + *this is a type guard that will narrow the type of whatever you pass in to + *[`Edge`](/api-reference/types/edge) if it returns `true`. * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true * @param element - The element to test * @returns A boolean indicating whether the element is an Edge + * + * @example + * ```js + *import { isEdge } from '@xyflow/react'; + * + *if (isEdge(edge)) { + * // .. + *} + *``` */ export const isEdge = (element: unknown): element is EdgeType => isEdgeBase(element); diff --git a/packages/system/package.json b/packages/system/package.json index c7b1ee03..dfb81e1c 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -46,7 +46,7 @@ "scripts": { "dev": "concurrently \"rollup --config node:@xyflow/rollup-config --watch\"", "build": "rollup --config node:@xyflow/rollup-config --environment NODE_ENV:production", - "lint": "eslint --ext .js,.ts src", + "lint": "eslint --ext .js,.ts src --fix", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index 39dc97bd..990729c3 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -12,11 +12,13 @@ export type EdgeBase< source: string; /** Id of target node */ target: string; - /** Id of source handle + /** + * Id of source handle * only needed if there are multiple handles per node */ sourceHandle?: string | null; - /** Id of target handle + /** + * Id of target handle * only needed if there are multiple handles per node */ targetHandle?: string | null; @@ -27,11 +29,13 @@ export type EdgeBase< /** Arbitrary data passed to an edge */ data?: EdgeData; selected?: boolean; - /** Set the marker on the beginning of an edge + /** + * Set the marker on the beginning of an edge * @example 'arrow', 'arrowclosed' or custom marker */ markerStart?: EdgeMarkerType; - /** Set the marker on the end of an edge + /** + * Set the marker on the end of an edge * @example 'arrow', 'arrowclosed' or custom marker */ markerEnd?: EdgeMarkerType; diff --git a/packages/system/src/types/handles.ts b/packages/system/src/types/handles.ts index 9cf2a1dd..ef67d373 100644 --- a/packages/system/src/types/handles.ts +++ b/packages/system/src/types/handles.ts @@ -14,11 +14,13 @@ export type Handle = { }; export type HandleProps = { - /** Type of the handle + /** + * Type of the handle * @example HandleType.Source, HandleType.Target */ type: HandleType; - /** Position of the handle + /** + * Position of the handle * @example Position.TopLeft, Position.TopRight, * Position.BottomLeft, Position.BottomRight */ @@ -29,11 +31,13 @@ export type HandleProps = { isConnectableStart?: boolean; /** Should you be able to connect to this handle */ isConnectableEnd?: boolean; - /** Callback if connection is valid + /** + * Callback if connection is valid * @remarks connection becomes an edge if isValidConnection returns true */ isValidConnection?: IsValidConnection; - /** Id of the handle + /** + * Id of the handle * @remarks optional if there is only one handle of this type */ id?: string | null; diff --git a/packages/system/src/types/nodes.ts b/packages/system/src/types/nodes.ts index 92261205..f1babd12 100644 --- a/packages/system/src/types/nodes.ts +++ b/packages/system/src/types/nodes.ts @@ -13,7 +13,8 @@ export type NodeBase< > = { /** Unique id of a node */ id: string; - /** Position of a node on the pane + /** + * Position of a node on the pane * @example { x: 0, y: 0 } */ position: XYPosition; @@ -21,11 +22,13 @@ export type NodeBase< data: NodeData; /** Type of node defined in nodeTypes */ type?: NodeType; - /** Only relevant for default, source, target nodeType. controls source position + /** + * Only relevant for default, source, target nodeType. controls source position * @example 'right', 'left', 'top', 'bottom' */ sourcePosition?: Position; - /** Only relevant for default, source, target nodeType. controls target position + /** + * Only relevant for default, source, target nodeType. controls target position * @example 'right', 'left', 'top', 'bottom' */ targetPosition?: Position; @@ -45,13 +48,15 @@ export type NodeBase< /** Parent node id, used for creating sub-flows */ parentId?: string; zIndex?: number; - /** Boundary a node can be moved in + /** + * Boundary a node can be moved in * @example 'parent' or [[0, 0], [100, 100]] */ extent?: 'parent' | CoordinateExtent; expandParent?: boolean; ariaLabel?: string; - /** Origin of the node relative to it's position + /** + * Origin of the node relative to it's position * @example * [0.5, 0.5] // centers the node * [0, 0] // top left @@ -73,8 +78,10 @@ export type InternalNodeBase = NodeType & internals: { positionAbsolute: XYPosition; z: number; - /** Holds a reference to the original node object provided by the user. - * Used as an optimization to avoid certain operations. */ + /** + * Holds a reference to the original node object provided by the user. + * Used as an optimization to avoid certain operations. + */ userNode: NodeType; handleBounds?: NodeHandleBounds; bounds?: NodeBounds; diff --git a/packages/system/src/utils/dom.ts b/packages/system/src/utils/dom.ts index 12188e9b..2311153f 100644 --- a/packages/system/src/utils/dom.ts +++ b/packages/system/src/utils/dom.ts @@ -61,9 +61,11 @@ export const getEventPosition = (event: MouseEvent | TouchEvent, bounds?: DOMRec }; }; -// The handle bounds are calculated relative to the node element. -// We store them in the internals object of the node in order to avoid -// unnecessary recalculations. +/* + * The handle bounds are calculated relative to the node element. + * We store them in the internals object of the node in order to avoid + * unnecessary recalculations. + */ export const getHandleBounds = ( type: 'source' | 'target', nodeElement: HTMLDivElement, diff --git a/packages/system/src/utils/edges/bezier-edge.ts b/packages/system/src/utils/edges/bezier-edge.ts index 640deffa..3b373938 100644 --- a/packages/system/src/utils/edges/bezier-edge.ts +++ b/packages/system/src/utils/edges/bezier-edge.ts @@ -38,8 +38,10 @@ export function getBezierEdgeCenter({ targetControlX: number; targetControlY: number; }): [number, number, number, number] { - // cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate - // https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve + /* + * cubic bezier t=0.5 mid point, not the actual mid point, but easy to calculate + * https://stackoverflow.com/questions/67516101/how-to-find-distance-mid-point-of-bezier-curve + */ const centerX = sourceX * 0.125 + sourceControlX * 0.375 + targetControlX * 0.375 + targetX * 0.125; const centerY = sourceY * 0.125 + sourceControlY * 0.375 + targetControlY * 0.375 + targetY * 0.125; const offsetX = Math.abs(centerX - sourceX); @@ -70,7 +72,9 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurva } /** - * Get a bezier path from source to target handle + * The `getBezierPath` util returns everything you need to render a bezier edge + *between two nodes. + * @public * @param params.sourceX - The x position of the source handle * @param params.sourceY - The y position of the source handle * @param params.sourcePosition - The position of the source handle (default: Position.Bottom) @@ -80,17 +84,22 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurva * @param params.curvature - The curvature of the bezier edge * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label * @example + * ```js * const source = { x: 0, y: 20 }; - const target = { x: 150, y: 100 }; - - const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({ - sourceX: source.x, - sourceY: source.y, - sourcePosition: Position.Right, - targetX: target.x, - targetY: target.y, - targetPosition: Position.Left, -}); + * const target = { x: 150, y: 100 }; + * + * const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({ + * sourceX: source.x, + * sourceY: source.y, + * sourcePosition: Position.Right, + * targetX: target.x, + * targetY: target.y, + * targetPosition: Position.Left, + *}); + *``` + * + * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to + *work with multiple edge paths at once. */ export function getBezierPath({ sourceX, diff --git a/packages/system/src/utils/edges/general.ts b/packages/system/src/utils/edges/general.ts index 7dfa4b44..2a6fd7a5 100644 --- a/packages/system/src/utils/edges/general.ts +++ b/packages/system/src/utils/edges/general.ts @@ -90,12 +90,16 @@ const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => { }; /** - * This util is a convenience function to add a new Edge to an array of edges - * @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one. + * This util is a convenience function to add a new Edge to an array of edges. It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one. * @public * @param edgeParams - Either an Edge or a Connection you want to add * @param edges - The array of all current edges * @returns A new array of edges with the new edge added + * + * @remarks If an edge with the same `target` and `source` already exists (and the same + *`targetHandle` and `sourceHandle` if those are set), then this util won't add + *a new edge even if the `id` property is different. + * */ export const addEdge = ( edgeParams: EdgeType | Connection, @@ -137,12 +141,16 @@ export type ReconnectEdgeOptions = { }; /** - * A handy utility to reconnect an existing edge with new properties + * A handy utility to update an existing [`Edge`](/api-reference/types/edge) with new properties. + *This searches your edge array for an edge with a matching `id` and updates its + *properties with the connection you provide. * @param oldEdge - The edge you want to update * @param newConnection - The new connection you want to update the edge with * @param edges - The array of all current edges * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id * @returns the updated edges array + * + * @public */ export const reconnectEdge = ( oldEdge: EdgeType, diff --git a/packages/system/src/utils/edges/smoothstep-edge.ts b/packages/system/src/utils/edges/smoothstep-edge.ts index 5e57efcd..0771f357 100644 --- a/packages/system/src/utils/edges/smoothstep-edge.ts +++ b/packages/system/src/utils/edges/smoothstep-edge.ts @@ -38,8 +38,10 @@ const getDirection = ({ const distance = (a: XYPosition, b: XYPosition) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); -// ith this function we try to mimic a orthogonal edge routing behaviour -// It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges +/* + * ith this function we try to mimic a orthogonal edge routing behaviour + * It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges + */ function getPoints({ source, sourcePosition = Position.Bottom, @@ -83,16 +85,20 @@ function getPoints({ if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) { centerX = center.x ?? defaultCenterX; centerY = center.y ?? defaultCenterY; - // ---> - // | - // >--- + /* + * ---> + * | + * >--- + */ const verticalSplit: XYPosition[] = [ { x: centerX, y: sourceGapped.y }, { x: centerX, y: targetGapped.y }, ]; - // | - // --- - // | + /* + * | + * --- + * | + */ const horizontalSplit: XYPosition[] = [ { x: sourceGapped.x, y: centerY }, { x: targetGapped.x, y: centerY }, @@ -191,7 +197,10 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str } /** - * Get a smooth step path from source to target handle + * The `getSmoothStepPath` util returns everything you need to render a stepped path + *between two nodes. The `borderRadius` property can be used to choose how rounded + *the corners of those steps are. + * @public * @param params.sourceX - The x position of the source handle * @param params.sourceY - The y position of the source handle * @param params.sourcePosition - The position of the source handle (default: Position.Bottom) @@ -200,17 +209,20 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str * @param params.targetPosition - The position of the target handle (default: Position.Top) * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label * @example + * ```js * const source = { x: 0, y: 20 }; - const target = { x: 150, y: 100 }; - - const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({ - sourceX: source.x, - sourceY: source.y, - sourcePosition: Position.Right, - targetX: target.x, - targetY: target.y, - targetPosition: Position.Left, - }); + * const target = { x: 150, y: 100 }; + * + * const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({ + * sourceX: source.x, + * sourceY: source.y, + * sourcePosition: Position.Right, + * targetX: target.x, + * targetY: target.y, + * targetPosition: Position.Left, + * }); + * ``` + * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once. */ export function getSmoothStepPath({ sourceX, diff --git a/packages/system/src/utils/edges/straight-edge.ts b/packages/system/src/utils/edges/straight-edge.ts index 9940bfea..baa7093b 100644 --- a/packages/system/src/utils/edges/straight-edge.ts +++ b/packages/system/src/utils/edges/straight-edge.ts @@ -8,24 +8,28 @@ export type GetStraightPathParams = { }; /** - * Get a straight path from source to target handle + * Calculates the straight line path between two points. + * @public * @param params.sourceX - The x position of the source handle * @param params.sourceY - The y position of the source handle * @param params.targetX - The x position of the target handle * @param params.targetY - The y position of the target handle * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label * @example + * ```js * const source = { x: 0, y: 20 }; - const target = { x: 150, y: 100 }; - - const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({ - sourceX: source.x, - sourceY: source.y, - sourcePosition: Position.Right, - targetX: target.x, - targetY: target.y, - targetPosition: Position.Left, - }); + * const target = { x: 150, y: 100 }; + * + * const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({ + * sourceX: source.x, + * sourceY: source.y, + * sourcePosition: Position.Right, + * targetX: target.x, + * targetY: target.y, + * targetPosition: Position.Left, + * }); + * ``` + * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once. */ export function getStraightPath({ sourceX, diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 7f631a59..32c339e5 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -186,8 +186,8 @@ export const rendererPointToPoint = ({ x, y }: XYPosition, [tx, ty, tScale]: Tra * @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport} * @example * const { x, y, zoom } = getViewportForBounds( - { x: 0, y: 0, width: 100, height: 100}, - 1200, 800, 0.5, 2); + *{ x: 0, y: 0, width: 100, height: 100}, + *1200, 800, 0.5, 2); */ export const getViewportForBounds = ( bounds: Rect, diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index ddec917c..1bb318d4 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -54,12 +54,27 @@ export const isInternalNodeBase = 'id' in element && 'internals' in element && !('source' in element) && !('target' in element); /** - * Pass in a node, and get connected nodes where edge.source === node.id + * This util is used to tell you what nodes, if any, are connected to the given node + *as the _target_ of an edge. * @public * @param node - The node to get the connected nodes from * @param nodes - The array of all nodes * @param edges - The array of all edges * @returns An array of nodes that are connected over eges where the source is the given node + * + * @example + * ```ts + *import { getOutgoers } from '@xyflow/react'; + * + *const nodes = []; + *const edges = []; + * + *const outgoers = getOutgoers( + * { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } }, + * nodes, + * edges, + *); + *``` */ export const getOutgoers = ( node: NodeType | { id: string }, @@ -81,12 +96,27 @@ export const getOutgoers = ( node: NodeType | { id: string }, @@ -124,12 +154,40 @@ export type GetNodesBoundsParams = { }; /** - * Internal function for determining a bounding box that contains all given nodes in an array. + * Returns the bounding box that contains all the given nodes in an array. This can + *be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds) + *to calculate the correct transform to fit the given nodes in a viewport. * @public * @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport. * @param nodes - Nodes to calculate the bounds for * @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center * @returns Bounding box enclosing all nodes + * + * @remarks This function was previously called `getRectOfNodes` + * + * @example + * ```js + *import { getNodesBounds } from '@xyflow/react'; + * + *const nodes = [ + * { + * id: 'a', + * position: { x: 0, y: 0 }, + * data: { label: 'a' }, + * width: 50, + * height: 25, + * }, + * { + * id: 'b', + * position: { x: 100, y: 100 }, + * data: { label: 'b' }, + * width: 50, + * height: 25, + * }, + *]; + * + *const bounds = getNodesBounds(nodes); + *``` */ export const getNodesBounds = ( nodes: (NodeType | InternalNodeBase | string)[], @@ -154,8 +212,8 @@ export const getNodesBounds = ( currentNode = isId ? params.nodeLookup.get(nodeOrId) : !isInternalNodeBase(nodeOrId) - ? params.nodeLookup.get(nodeOrId.id) - : nodeOrId; + ? params.nodeLookup.get(nodeOrId.id) + : nodeOrId; } const nodeBox = currentNode ? nodeToBox(currentNode, params.nodeOrigin) : { x: 0, y: 0, x2: 0, y2: 0 }; @@ -238,10 +296,29 @@ export const getNodesInside = ( }; /** - * Get all connecting edges for a given set of nodes + * This utility filters an array of edges, keeping only those where either the source or target node is present in the given array of nodes. + * @public * @param nodes - Nodes you want to get the connected edges for * @param edges - All edges * @returns Array of edges that connect any of the given nodes with each other + * + * @example + * ```js + *import { getConnectedEdges } from '@xyflow/react'; + * + *const nodes = [ + * { id: 'a', position: { x: 0, y: 0 } }, + * { id: 'b', position: { x: 100, y: 0 } }, + *]; + * + *const edges = [ + * { id: 'a->c', source: 'a', target: 'c' }, + * { id: 'c->d', source: 'c', target: 'd' }, + *]; + * + *const connectedEdges = getConnectedEdges(nodes, edges); + * // => [{ id: 'a->c', source: 'a', target: 'c' }] + *``` */ export const getConnectedEdges = ( nodes: NodeType[], @@ -382,9 +459,9 @@ export async function getElementsToRemove; }): Promise<{ - nodes: NodeType[]; - edges: EdgeType[]; -}> { + nodes: NodeType[]; + edges: EdgeType[]; + }> { const nodeIds = new Set(nodesToRemove.map((node) => node.id)); const matchingNodes: NodeType[] = []; diff --git a/packages/system/src/utils/node-toolbar.ts b/packages/system/src/utils/node-toolbar.ts index 1813513c..f5246bcc 100644 --- a/packages/system/src/utils/node-toolbar.ts +++ b/packages/system/src/utils/node-toolbar.ts @@ -15,8 +15,10 @@ export function getNodeToolbarTransform( alignmentOffset = 1; } - // position === Position.Top - // we set the x any y position of the toolbar based on the nodes position + /* + * position === Position.Top + * we set the x any y position of the toolbar based on the nodes position + */ let pos = [ (nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x, nodeRect.y * viewport.zoom + viewport.y - offset, diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 77c5b369..a9d13316 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -276,8 +276,10 @@ export function handleExpandParent( }, }); - // We move all child nodes in the oppsite direction - // so the x,y changes of the parent do not move the children + /* + * We move all child nodes in the oppsite direction + * so the x,y changes of the parent do not move the children + */ parentLookup.get(parentId)?.forEach((childNode) => { if (!children.some((child) => child.id === childNode.id)) { changes.push({ @@ -472,9 +474,11 @@ function addConnectionToLookup( nodeId: string, handleId: string | null ) { - // We add the connection to the connectionLookup at the following keys - // 1. nodeId, 2. nodeId-type, 3. nodeId-type-handleId - // If the key already exists, we add the connection to the existing map + /* + * We add the connection to the connectionLookup at the following keys + * 1. nodeId, 2. nodeId-type, 3. nodeId-type-handleId + * If the key already exists, we add the connection to the existing map + */ let key = nodeId; const nodeMap = connectionLookup.get(key) || new Map(); connectionLookup.set(key, nodeMap.set(connectionKey, connection)); diff --git a/packages/system/src/xydrag/XYDrag.ts b/packages/system/src/xydrag/XYDrag.ts index eb2ea80a..be0fa93a 100644 --- a/packages/system/src/xydrag/XYDrag.ts +++ b/packages/system/src/xydrag/XYDrag.ts @@ -140,8 +140,10 @@ export function XYDrag voi for (const [id, dragItem] of dragItems) { if (!nodeLookup.has(id)) { - // if the node is not in the nodeLookup anymore, it was probably deleted while dragging - // and we don't need to update it anymore + /* + * if the node is not in the nodeLookup anymore, it was probably deleted while dragging + * and we don't need to update it anymore + */ continue; } @@ -150,8 +152,10 @@ export function XYDrag voi nextPosition = snapPosition(nextPosition, snapGrid); } - // if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node - // based on its position so that the node stays at it's position relative to the selection. + /* + * if there is selection with multiple nodes and a node extent is set, we need to adjust the node extent for each node + * based on its position so that the node stays at it's position relative to the selection. + */ let adjustedNodeExtent: CoordinateExtent = [ [nodeExtent[0][0], nodeExtent[0][1]], [nodeExtent[1][0], nodeExtent[1][1]], diff --git a/packages/system/src/xydrag/utils.ts b/packages/system/src/xydrag/utils.ts index 5c0eda0a..dc980281 100644 --- a/packages/system/src/xydrag/utils.ts +++ b/packages/system/src/xydrag/utils.ts @@ -74,9 +74,11 @@ export function getDragItems( return dragItems; } -// returns two params: -// 1. the dragged node (or the first of the list, if we are dragging a node selection) -// 2. array of selected nodes (for multi selections) +/* + * returns two params: + * 1. the dragged node (or the first of the list, if we are dragging a node selection) + * 2. array of selected nodes (for multi selections) + */ export function getEventHandlerParams({ nodeId, dragItems, @@ -112,10 +114,10 @@ export function getEventHandlerParams({ !node ? nodesFromDragItems[0] : { - ...node, - position: dragItems.get(nodeId)?.position || node.position, - dragging, - }, + ...node, + position: dragItems.get(nodeId)?.position || node.position, + dragging, + }, nodesFromDragItems, ]; } diff --git a/packages/system/src/xyhandle/XYHandle.ts b/packages/system/src/xyhandle/XYHandle.ts index 5f4fc610..9c2af456 100644 --- a/packages/system/src/xyhandle/XYHandle.ts +++ b/packages/system/src/xyhandle/XYHandle.ts @@ -165,8 +165,10 @@ function onPointerDown( toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId)! : null, }; - // we don't want to trigger an update when the connection - // is snapped to the same handle as before + /* + * we don't want to trigger an update when the connection + * is snapped to the same handle as before + */ if ( isValid && closestHandle && @@ -190,8 +192,10 @@ function onPointerDown( onConnect?.(connection); } - // it's important to get a fresh reference from the store here - // in order to get the latest state of onConnectEnd + /* + * it's important to get a fresh reference from the store here + * in order to get the latest state of onConnectEnd + */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const { inProgress, ...connectionState } = previousConnection; const finalConnectionState = { @@ -248,8 +252,10 @@ function isValidHandle( const { x, y } = getEventPosition(event); const handleBelow = doc.elementFromPoint(x, y); - // we always want to prioritize the handle below the mouse cursor over the closest distance handle, - // because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor + /* + * we always want to prioritize the handle below the mouse cursor over the closest distance handle, + * because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor + */ const handleToCheck = handleBelow?.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode; const result: Result = { diff --git a/packages/system/src/xyhandle/utils.ts b/packages/system/src/xyhandle/utils.ts index ecc9b1cc..4650f192 100644 --- a/packages/system/src/xyhandle/utils.ts +++ b/packages/system/src/xyhandle/utils.ts @@ -19,8 +19,10 @@ function getNodesWithinDistance(position: XYPosition, nodeLookup: NodeLookup, di return nodes; } -// this distance is used for the area around the user pointer -// while doing a connection for finding the closest nodes +/* + * this distance is used for the area around the user pointer + * while doing a connection for finding the closest nodes + */ const ADDITIONAL_DISTANCE = 250; export function getClosestHandle( diff --git a/packages/system/src/xypanzoom/XYPanZoom.ts b/packages/system/src/xypanzoom/XYPanZoom.ts index 54b97e30..93bc79f8 100644 --- a/packages/system/src/xypanzoom/XYPanZoom.ts +++ b/packages/system/src/xypanzoom/XYPanZoom.ts @@ -114,22 +114,22 @@ export function XYPanZoom({ const wheelHandler = isPanOnScroll ? createPanOnScrollHandler({ - zoomPanValues, - noWheelClassName, - d3Selection, - d3Zoom: d3ZoomInstance, - panOnScrollMode, - panOnScrollSpeed, - zoomOnPinch, - onPanZoomStart, - onPanZoom, - onPanZoomEnd, - }) + zoomPanValues, + noWheelClassName, + d3Selection, + d3Zoom: d3ZoomInstance, + panOnScrollMode, + panOnScrollSpeed, + zoomOnPinch, + onPanZoomStart, + onPanZoom, + onPanZoomEnd, + }) : createZoomOnScrollHandler({ - noWheelClassName, - preventScrolling, - d3ZoomHandler, - }); + noWheelClassName, + preventScrolling, + d3ZoomHandler, + }); d3Selection.on('wheel.zoom', wheelHandler, { passive: false }); @@ -178,9 +178,11 @@ export function XYPanZoom({ }); d3ZoomInstance.filter(filter); - // We cannot add zoomOnDoubleClick to the filter above because - // double tapping on touch screens circumvents the filter and - // dblclick.zoom is fired on the selection directly + /* + * We cannot add zoomOnDoubleClick to the filter above because + * double tapping on touch screens circumvents the filter and + * dblclick.zoom is fired on the selection directly + */ if (zoomOnDoubleClick) { d3Selection.on('dblclick.zoom', d3DblClickZoomHandler); } else { diff --git a/packages/system/src/xypanzoom/eventhandler.ts b/packages/system/src/xypanzoom/eventhandler.ts index 2e78b90a..751a31c5 100644 --- a/packages/system/src/xypanzoom/eventhandler.ts +++ b/packages/system/src/xypanzoom/eventhandler.ts @@ -90,8 +90,10 @@ export function createPanOnScrollHandler({ return; } - // increase scroll speed in firefox - // firefox: deltaMode === 1; chrome: deltaMode === 0 + /* + * increase scroll speed in firefox + * firefox: deltaMode === 1; chrome: deltaMode === 0 + */ const deltaNormalize = event.deltaMode === 1 ? 20 : 1; let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize; let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize; @@ -114,9 +116,11 @@ export function createPanOnScrollHandler({ clearTimeout(zoomPanValues.panScrollTimeout); - // for pan on scroll we need to handle the event calls on our own - // we can't use the start, zoom and end events from d3-zoom - // because start and move gets called on every scroll event and not once at the beginning + /* + * for pan on scroll we need to handle the event calls on our own + * we can't use the start, zoom and end events from d3-zoom + * because start and move gets called on every scroll event and not once at the beginning + */ if (!zoomPanValues.isPanScrolling) { zoomPanValues.isPanScrolling = true; diff --git a/packages/system/src/xyresizer/XYResizer.ts b/packages/system/src/xyresizer/XYResizer.ts index 1f4ba321..44dd1ac6 100644 --- a/packages/system/src/xyresizer/XYResizer.ts +++ b/packages/system/src/xyresizer/XYResizer.ts @@ -154,8 +154,10 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X parentExtent = parentNode && node.extent === 'parent' ? nodeToParentExtent(parentNode) : undefined; } - // Collect all child nodes to correct their relative positions when top/left changes - // Determine largest minimal extent the parent node is allowed to resize to + /* + * Collect all child nodes to correct their relative positions when top/left changes + * Determine largest minimal extent the parent node is allowed to resize to + */ childNodes = []; childExtent = undefined; @@ -230,8 +232,10 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X prevValues.x = change.x; prevValues.y = change.y; - // when top/left changes, correct the relative positions of child nodes - // so that they stay in the same position + /* + * when top/left changes, correct the relative positions of child nodes + * so that they stay in the same position + */ if (childNodes.length > 0) { const xChange = x - prevX; const yChange = y - prevY; From 0848bc936701193c5ac122e8fd45da11d0670341 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 15:31:19 +0100 Subject: [PATCH 011/157] chore(components): add tsdocs for rf and provider --- .../src/components/Edges/SimpleBezierEdge.tsx | 2 +- .../components/ReactFlowProvider/index.tsx | 35 +++++++++++++++++++ .../react/src/container/ReactFlow/index.tsx | 20 +++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/Edges/SimpleBezierEdge.tsx b/packages/react/src/components/Edges/SimpleBezierEdge.tsx index 102c163e..1c8c2697 100644 --- a/packages/react/src/components/Edges/SimpleBezierEdge.tsx +++ b/packages/react/src/components/Edges/SimpleBezierEdge.tsx @@ -31,7 +31,7 @@ function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] /** * The `getSimpleBezierPath` util returns everything you need to render a simple -bezier edge between two nodes. + *bezier edge between two nodes. * @public */ export function getSimpleBezierPath({ diff --git a/packages/react/src/components/ReactFlowProvider/index.tsx b/packages/react/src/components/ReactFlowProvider/index.tsx index b29f5f17..b8b4bf40 100644 --- a/packages/react/src/components/ReactFlowProvider/index.tsx +++ b/packages/react/src/components/ReactFlowProvider/index.tsx @@ -19,6 +19,41 @@ export type ReactFlowProviderProps = { children: ReactNode; }; +/** + * The `` component is a + *[context provider](https://react.dev/learn/passing-data-deeply-with-context#) that + *makes it possible to access a flow's internal state outside of the + *[``](/api-reference/react-flow) component. Many of the hooks we + *provide rely on this component to work. + * @public + * + * @example + * ```tsx + *import { ReactFlow, ReactFlowProvider, useNodes } from '@xyflow/react' + * + *export default function Flow() { + * return ( + * + * + * + * + * ); + *} + * + *function Sidebar() { + * // This hook will only work if the component it's used in is a child of a + * // . + * const nodes = useNodes() + * + * return ; + *} + *``` + * + * @remarks If you're using a router and want your flow's state to persist across routes, + *it's vital that you place the `` component _outside_ of + *your router. If you have multiple flows on the same page you will need to use a separate + *`` for each flow. + */ export function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index 82206fc8..c9b504aa 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -301,4 +301,24 @@ function ReactFlow( ); } +/** + * The `` component is the heart of your React Flow application. It + *renders your nodes and edges and handles user interaction + * + * @public + * + * @example + * ```tsx + *import { ReactFlow } from '@xyflow/react' + * + *export default function Flow() { + * return (); + *} + *``` + */ export default fixedForwardRef(ReactFlow); From 7b0f96f0177c004a21bd59e346c1ef228d7087f7 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 15:47:56 +0100 Subject: [PATCH 012/157] chore(types): add tsdocs --- packages/system/src/types/changes.ts | 13 ++++++++++++- packages/system/src/types/edges.ts | 20 ++++++++++++++++++++ packages/system/src/types/general.ts | 13 +++++++++++++ packages/system/src/types/utils.ts | 10 ++++++++++ packages/system/src/utils/edges/general.ts | 9 +++++++-- 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/packages/system/src/types/changes.ts b/packages/system/src/types/changes.ts index 9b232733..8ab81a37 100644 --- a/packages/system/src/types/changes.ts +++ b/packages/system/src/types/changes.ts @@ -42,7 +42,10 @@ export type NodeReplaceChange = { }; /** - * Union type of all possible node changes. + * The [`onNodesChange`](/api-reference/react-flow#on-nodes-change) callback takes + *an array of `NodeChange` objects that you should use to update your flow's state. + *The `NodeChange` type is a union of six different object types that represent that + *various ways an node can change in a flow. * @public */ export type NodeChange = @@ -67,6 +70,14 @@ export type EdgeReplaceChange = { type: 'replace'; }; +/** + * The [`onEdgesChange`](/api-reference/react-flow#on-edges-change) callback takes + *an array of `EdgeChange` objects that you should use to update your flow's state. + *The `EdgeChange` type is a union of four different object types that represent that + *various ways an edge can change in a flow. + * + * @public + */ export type EdgeChange = | EdgeSelectionChange | EdgeRemoveChange diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index 990729c3..abe7c8f2 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -58,11 +58,24 @@ export type BezierPathOptions = { curvature?: number; }; +/** + * @inline + */ export type DefaultEdgeOptionsBase = Omit< EdgeType, 'id' | 'source' | 'target' | 'sourceHandle' | 'targetHandle' | 'selected' >; +/** + * If you set the `connectionLineType` prop on your [``](/api-reference/react-flow#connection-connectionLineType) + *component, it will dictate the style of connection line rendered when creating + *new edges. + * + * @public + * + * @remarks If you choose to render a custom connection line component, this value will be + *passed to your component as part of its [`ConnectionLineComponentProps`](/api-reference/types/connection-line-component-props). + */ export enum ConnectionLineType { Bezier = 'default', Straight = 'straight', @@ -71,6 +84,13 @@ export enum ConnectionLineType { SimpleBezier = 'simplebezier', } +/** + * Edges can optionally have markers at the start and end of an edge. The `EdgeMarker` + *type is used to configure those markers! Check the docs for [`MarkerType`](/api-reference/types/marker-type) + *for details on what types of edge marker are available. + * + * @public + */ export type EdgeMarker = { type: MarkerType; color?: string; diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 3c6eed52..485bb4f5 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -26,6 +26,13 @@ export type SetViewport = (viewport: Viewport, options?: ViewportHelperFunctionO export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => Promise; export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => Promise; +/** + * The `Connection` type is the basic minimal description of an [`Edge`](/api-reference/types/edge) + *between two nodes. The [`addEdge`](/api-reference/utils/add-edge) util can be used to upgrade + *a `Connection` to an [`Edge`](/api-reference/types/edge). + * + * @public + */ export type Connection = { source: string; target: string; @@ -174,6 +181,12 @@ export type ConnectionInProgress = | ConnectionInProgress | NoConnection; diff --git a/packages/system/src/types/utils.ts b/packages/system/src/types/utils.ts index b06786a7..61d55698 100644 --- a/packages/system/src/types/utils.ts +++ b/packages/system/src/types/utils.ts @@ -33,4 +33,14 @@ export type Box = XYPosition & { export type Transform = [number, number, number]; +/** + * A coordinate extent represents two points in a coordinate system: one in the top + *left corner and one in the bottom right corner. It is used to represent the + *bounds of nodes in the flow or the bounds of the viewport. + * + * @public + * + * @remarks Props that expect a `CoordinateExtent` usually default to `[[-∞, -∞], [+∞, +∞]]` + *to represent an unbounded extent. + */ export type CoordinateExtent = [[number, number], [number, number]]; diff --git a/packages/system/src/utils/edges/general.ts b/packages/system/src/utils/edges/general.ts index 2a6fd7a5..7f98d00f 100644 --- a/packages/system/src/utils/edges/general.ts +++ b/packages/system/src/utils/edges/general.ts @@ -144,13 +144,18 @@ export type ReconnectEdgeOptions = { * A handy utility to update an existing [`Edge`](/api-reference/types/edge) with new properties. *This searches your edge array for an edge with a matching `id` and updates its *properties with the connection you provide. + * @public * @param oldEdge - The edge you want to update * @param newConnection - The new connection you want to update the edge with * @param edges - The array of all current edges * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id * @returns the updated edges array - * - * @public + * + * @example + * ```js + *const onReconnect = useCallback( + * (oldEdge: Edge, newConnection: Connection) => setEdges((els) => reconnectEdge(oldEdge, newConnection, els)),[]); + *``` */ export const reconnectEdge = ( oldEdge: EdgeType, From 381ed2a5bf01bde4cf44b34faa2e464fbc0b6305 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 11 Feb 2025 17:57:21 +0100 Subject: [PATCH 013/157] chore(types): add tsdocs --- .../additional-components/Background/types.ts | 9 +++ .../Controls/ControlButton.tsx | 2 +- .../Controls/Controls.tsx | 5 +- .../additional-components/MiniMap/MiniMap.tsx | 16 ++--- .../additional-components/MiniMap/types.ts | 5 ++ .../NodeResizer/NodeResizer.tsx | 2 +- .../NodeToolbar/NodeToolbar.tsx | 7 +-- .../components/EdgeLabelRenderer/index.tsx | 13 ++--- .../react/src/components/Edges/BaseEdge.tsx | 10 ++-- .../react/src/components/Edges/EdgeText.tsx | 2 +- .../src/components/Edges/SimpleBezierEdge.tsx | 4 +- .../react/src/components/Handle/index.tsx | 2 +- packages/react/src/components/Panel/index.tsx | 6 +- .../components/ReactFlowProvider/index.tsx | 15 +++-- .../src/components/ViewportPortal/index.tsx | 7 ++- .../react/src/container/ReactFlow/index.tsx | 4 +- packages/react/src/contexts/NodeIdContext.ts | 4 +- packages/react/src/hooks/useConnection.ts | 6 +- packages/react/src/hooks/useEdges.ts | 2 +- packages/react/src/hooks/useInternalNode.ts | 6 +- packages/react/src/hooks/useKeyPress.ts | 2 +- packages/react/src/hooks/useNodes.ts | 4 +- .../react/src/hooks/useNodesEdgesState.ts | 22 +++---- packages/react/src/hooks/useStore.ts | 12 ++-- packages/react/src/types/edges.ts | 23 +++++++- packages/react/src/types/general.ts | 11 ++++ packages/react/src/types/instance.ts | 8 +++ packages/react/src/types/nodes.ts | 38 ++++++++++-- packages/react/src/utils/general.ts | 14 +++-- packages/svelte/src/lib/types/edges.ts | 4 +- packages/system/src/types/edges.ts | 6 ++ packages/system/src/types/general.ts | 58 +++++++++++++++++-- packages/system/src/types/nodes.ts | 17 +++++- packages/system/src/types/utils.ts | 18 +++++- 34 files changed, 264 insertions(+), 100 deletions(-) diff --git a/packages/react/src/additional-components/Background/types.ts b/packages/react/src/additional-components/Background/types.ts index 9d1cd67b..50219e2d 100644 --- a/packages/react/src/additional-components/Background/types.ts +++ b/packages/react/src/additional-components/Background/types.ts @@ -1,11 +1,20 @@ import { CSSProperties } from 'react'; +/** + * The three variants are exported as an enum for convenience. You can either import + * the enum and use it like `BackgroundVariant.Lines` or you can use the raw string + * value directly. + * @public + */ export enum BackgroundVariant { Lines = 'lines', Dots = 'dots', Cross = 'cross', } +/** + * @expand + */ export type BackgroundProps = { id?: string; /** Color of the pattern */ diff --git a/packages/react/src/additional-components/Controls/ControlButton.tsx b/packages/react/src/additional-components/Controls/ControlButton.tsx index 12c58663..a3cc81ad 100644 --- a/packages/react/src/additional-components/Controls/ControlButton.tsx +++ b/packages/react/src/additional-components/Controls/ControlButton.tsx @@ -4,7 +4,7 @@ import type { ControlButtonProps } from './types'; /** * You can add buttons to the control panel by using the `` component - *and pass it as a child to the [``](/api-reference/components/controls) component. + * and pass it as a child to the [``](/api-reference/components/controls) component. * * @public * @example diff --git a/packages/react/src/additional-components/Controls/Controls.tsx b/packages/react/src/additional-components/Controls/Controls.tsx index 1b0beae3..84337a28 100644 --- a/packages/react/src/additional-components/Controls/Controls.tsx +++ b/packages/react/src/additional-components/Controls/Controls.tsx @@ -127,7 +127,7 @@ ControlsComponent.displayName = 'Controls'; /** * The `` component renders a small panel that contains convenient - *buttons to zoom in, zoom out, fit the view, and lock the viewport. + * buttons to zoom in, zoom out, fit the view, and lock the viewport. * * @public * @example @@ -143,8 +143,7 @@ ControlsComponent.displayName = 'Controls'; *} *``` * - * @remarks To extend or customise the controls, you can use the [``](/api-reference/components/control-button) - *component + * @remarks To extend or customise the controls, you can use the [``](/api-reference/components/control-button) component * */ export const Controls = memo(ControlsComponent); diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index c5e8d719..be6dc453 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -113,16 +113,16 @@ function MiniMapComponent({ const onSvgClick = onClick ? (event: MouseEvent) => { - const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; - onClick(event, { x, y }); - } + const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; + onClick(event, { x, y }); + } : undefined; const onSvgNodeClick = onNodeClick ? useCallback((event: MouseEvent, nodeId: string) => { - const node = store.getState().nodeLookup.get(nodeId)!; - onNodeClick(event, node); - }, []) + const node = store.getState().nodeLookup.get(nodeId)!; + onNodeClick(event, node); + }, []) : undefined; return ( @@ -180,8 +180,8 @@ MiniMapComponent.displayName = 'MiniMap'; /** * The `` component can be used to render an overview of your flow. It - *renders each node as an SVG element and visualizes where the current viewport is - *in relation to the rest of the flow. + * renders each node as an SVG element and visualizes where the current viewport is + * in relation to the rest of the flow. * * @public * @example diff --git a/packages/react/src/additional-components/MiniMap/types.ts b/packages/react/src/additional-components/MiniMap/types.ts index c6d11ba8..351395f9 100644 --- a/packages/react/src/additional-components/MiniMap/types.ts +++ b/packages/react/src/additional-components/MiniMap/types.ts @@ -58,6 +58,11 @@ export type MiniMapNodes = Pick< onClick?: (event: MouseEvent, nodeId: string) => void; }; +/** + * The props that are passed to the MiniMapNode component + * + * @public + */ export type MiniMapNodeProps = { id: string; x: number; diff --git a/packages/react/src/additional-components/NodeResizer/NodeResizer.tsx b/packages/react/src/additional-components/NodeResizer/NodeResizer.tsx index f3e6cf8a..434be4b7 100644 --- a/packages/react/src/additional-components/NodeResizer/NodeResizer.tsx +++ b/packages/react/src/additional-components/NodeResizer/NodeResizer.tsx @@ -5,7 +5,7 @@ import type { NodeResizerProps } from './types'; /** * The `` component can be used to add a resize functionality to your - *nodes. It renders draggable controls around the node to resize in all directions. + * nodes. It renders draggable controls around the node to resize in all directions. * @public * * @example diff --git a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx index 4e486425..0248b394 100644 --- a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx +++ b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx @@ -40,7 +40,7 @@ const storeSelector = (state: ReactFlowState) => ({ /** * This component can render a toolbar or tooltip to one side of a custom node. This - *toolbar doesn't scale with the viewport so that the content is always visible. + * toolbar doesn't scale with the viewport so that the content is always visible. * * @public * @example @@ -70,9 +70,8 @@ const storeSelector = (state: ReactFlowState) => ({ *export default memo(CustomNode); *``` * @remarks By default, the toolbar is only visible when a node is selected. If multiple - *nodes are selected it will not be visible to prevent overlapping toolbars or - *clutter. You can override this behavior by setting the `isVisible` prop to - *`true`. + * nodes are selected it will not be visible to prevent overlapping toolbars or + * clutter. You can override this behavior by setting the `isVisible` prop to `true`. */ export function NodeToolbar({ nodeId, diff --git a/packages/react/src/components/EdgeLabelRenderer/index.tsx b/packages/react/src/components/EdgeLabelRenderer/index.tsx index b3aa1a91..647811cb 100644 --- a/packages/react/src/components/EdgeLabelRenderer/index.tsx +++ b/packages/react/src/components/EdgeLabelRenderer/index.tsx @@ -8,10 +8,9 @@ const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__e /** * Edges are SVG-based. If you want to render more complex labels you can use the - *`` component to access a div based renderer. This component - *is a portal that renders the label in a `
` that is positioned on top of - *the edges. You can see an example usage of the component in the [edge label renderer](/examples/edges/edge-label-renderer) - *example. + * `` component to access a div based renderer. This component + * is a portal that renders the label in a `
` that is positioned on top of + * the edges. You can see an example usage of the component in the [edge label renderer](/examples/edges/edge-label-renderer) example. * @public * * @example @@ -43,9 +42,9 @@ const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__e *}; *``` * - *@remarks The `` has no pointer events by default. If you want to - *add mouse interactions you need to set the style `pointerEvents: all` and add - *the `nopan` class on the label or the element you want to interact with. + * @remarks The `` has no pointer events by default. If you want to + * add mouse interactions you need to set the style `pointerEvents: all` and add + * the `nopan` class on the label or the element you want to interact with. */ export function EdgeLabelRenderer({ children }: { children: ReactNode }) { const edgeLabelRenderer = useStore(selector); diff --git a/packages/react/src/components/Edges/BaseEdge.tsx b/packages/react/src/components/Edges/BaseEdge.tsx index e19412f2..4d1ac1da 100644 --- a/packages/react/src/components/Edges/BaseEdge.tsx +++ b/packages/react/src/components/Edges/BaseEdge.tsx @@ -6,8 +6,8 @@ import type { BaseEdgeProps } from '../../types'; /** * The `` component gets used internally for all the edges. It can be - *used inside a custom edge and handles the invisible helper edge and the edge label - *for you. + * used inside a custom edge and handles the invisible helper edge and the edge label + * for you. * * @public * @example @@ -27,9 +27,9 @@ import type { BaseEdgeProps } from '../../types'; *``` * * @remarks If you want to use an edge marker with the [``](/api-reference/components/base-edge) component, - *you can pass the `markerStart` or `markerEnd` props passed to your custom edge - *through to the [``](/api-reference/components/base-edge) component. You can see all the props - *passed to a custom edge by looking at the [`EdgeProps`](/api-reference/types/edge-props) type. + * you can pass the `markerStart` or `markerEnd` props passed to your custom edge + * through to the [``](/api-reference/components/base-edge) component. + * You can see all the props passed to a custom edge by looking at the [`EdgeProps`](/api-reference/types/edge-props) type. */ export function BaseEdge({ path, diff --git a/packages/react/src/components/Edges/EdgeText.tsx b/packages/react/src/components/Edges/EdgeText.tsx index e2d162b0..2c79f718 100644 --- a/packages/react/src/components/Edges/EdgeText.tsx +++ b/packages/react/src/components/Edges/EdgeText.tsx @@ -75,7 +75,7 @@ EdgeTextComponent.displayName = 'EdgeText'; /** * You can use the `` component as a helper component to display text - *within your custom edges. + * within your custom edges. * *@public * diff --git a/packages/react/src/components/Edges/SimpleBezierEdge.tsx b/packages/react/src/components/Edges/SimpleBezierEdge.tsx index 1c8c2697..a11cbc1d 100644 --- a/packages/react/src/components/Edges/SimpleBezierEdge.tsx +++ b/packages/react/src/components/Edges/SimpleBezierEdge.tsx @@ -31,8 +31,8 @@ function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] /** * The `getSimpleBezierPath` util returns everything you need to render a simple - *bezier edge between two nodes. - * @public + * bezier edge between two nodes. + * @public */ export function getSimpleBezierPath({ sourceX, diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index 07d18378..72e7ad21 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -251,7 +251,7 @@ function HandleComponent( /** * The `` component is used in your [custom nodes](/learn/customization/custom-nodes) - *to define connection points. + * to define connection points. * *@public * diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index 1859b034..461cc1ba 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -6,9 +6,9 @@ import { useStore } from '../../hooks/useStore'; import type { ReactFlowState } from '../../types'; /** - * The `` component helps you position content above the viewport. It is - *used internally by the [``](/api-reference/components/minimap) and [``](/api-reference/components/controls) - *components. + * The `` component helps you position content above the viewport. + * It is used internally by the [``](/api-reference/components/minimap) + * and [``](/api-reference/components/controls) components. * * @public * diff --git a/packages/react/src/components/ReactFlowProvider/index.tsx b/packages/react/src/components/ReactFlowProvider/index.tsx index b8b4bf40..1492ca3f 100644 --- a/packages/react/src/components/ReactFlowProvider/index.tsx +++ b/packages/react/src/components/ReactFlowProvider/index.tsx @@ -20,11 +20,10 @@ export type ReactFlowProviderProps = { }; /** - * The `` component is a - *[context provider](https://react.dev/learn/passing-data-deeply-with-context#) that - *makes it possible to access a flow's internal state outside of the - *[``](/api-reference/react-flow) component. Many of the hooks we - *provide rely on this component to work. + * The `` component is a [context provider](https://react.dev/learn/passing-data-deeply-with-context#) + * that makes it possible to access a flow's internal state outside of the + * [``](/api-reference/react-flow) component. Many of the hooks we + * provide rely on this component to work. * @public * * @example @@ -50,9 +49,9 @@ export type ReactFlowProviderProps = { *``` * * @remarks If you're using a router and want your flow's state to persist across routes, - *it's vital that you place the `` component _outside_ of - *your router. If you have multiple flows on the same page you will need to use a separate - *`` for each flow. + * it's vital that you place the `` component _outside_ of + * your router. If you have multiple flows on the same page you will need to use a separate + * `` for each flow. */ export function ReactFlowProvider({ initialNodes: nodes, diff --git a/packages/react/src/components/ViewportPortal/index.tsx b/packages/react/src/components/ViewportPortal/index.tsx index ea306935..1040d796 100644 --- a/packages/react/src/components/ViewportPortal/index.tsx +++ b/packages/react/src/components/ViewportPortal/index.tsx @@ -7,9 +7,10 @@ import type { ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__viewport-portal'); /** - * The `` component can be used to add components to the same viewport of the flow where nodes and edges are rendered. - *This is useful when you want to render your own components that are adhere to the same coordinate system as the nodes & edges and are also - *affected by zooming and panning + * The `` component can be used to add components to the same viewport + * of the flow where nodes and edges are rendered. This is useful when you want to render + * your own components that are adhere to the same coordinate system as the nodes & edges + * and are also affected by zooming and panning * @public * @example * diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index c9b504aa..439a84e6 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -302,8 +302,8 @@ function ReactFlow( } /** - * The `` component is the heart of your React Flow application. It - *renders your nodes and edges and handles user interaction + * The `` component is the heart of your React Flow application. + * It renders your nodes and edges and handles user interaction * * @public * diff --git a/packages/react/src/contexts/NodeIdContext.ts b/packages/react/src/contexts/NodeIdContext.ts index b5811ad6..5458c98c 100644 --- a/packages/react/src/contexts/NodeIdContext.ts +++ b/packages/react/src/contexts/NodeIdContext.ts @@ -6,8 +6,8 @@ export const Consumer = NodeIdContext.Consumer; /** * You can use this hook to get the id of the node it is used inside. It is useful - *if you need the node's id deeper in the render tree but don't want to manually - *drill down the id as a prop. + * if you need the node's id deeper in the render tree but don't want to manually + * drill down the id as a prop. * * @public * @returns id of the node diff --git a/packages/react/src/hooks/useConnection.ts b/packages/react/src/hooks/useConnection.ts index 8992d767..9ed14b67 100644 --- a/packages/react/src/hooks/useConnection.ts +++ b/packages/react/src/hooks/useConnection.ts @@ -25,9 +25,9 @@ function getSelector state.edges; /** * This hook returns an array of the current edges. Components that use this hook - *will re-render **whenever any edge changes**. + * will re-render **whenever any edge changes**. * * @public * @returns An array of edges diff --git a/packages/react/src/hooks/useInternalNode.ts b/packages/react/src/hooks/useInternalNode.ts index bfdc74f9..ecd83897 100644 --- a/packages/react/src/hooks/useInternalNode.ts +++ b/packages/react/src/hooks/useInternalNode.ts @@ -5,9 +5,9 @@ import { useStore } from './useStore'; import type { InternalNode, Node } from '../types'; /** - * This hook returns the internal representation of a specific node. Components that use this hook - *will re-render **whenever the node changes**, including when a node is selected - *or moved. + * This hook returns the internal representation of a specific node. + * Components that use this hook will re-render **whenever the node changes**, + * including when a node is selected or moved. * * @public * @param id - id of the node diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index 6f2d01c3..00cd012b 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -14,7 +14,7 @@ const defaultDoc = typeof document !== 'undefined' ? document : null; /** * This hook lets you listen for specific key codes and tells you whether they are - *currently pressed or not. + * currently pressed or not. * * @public * @param param.keyCode - The key code (string or array of strings) to use diff --git a/packages/react/src/hooks/useNodes.ts b/packages/react/src/hooks/useNodes.ts index c64f7fb1..9fa14bcb 100644 --- a/packages/react/src/hooks/useNodes.ts +++ b/packages/react/src/hooks/useNodes.ts @@ -7,8 +7,8 @@ const nodesSelector = (state: ReactFlowState) => state.nodes; /** * This hook returns an array of the current nodes. Components that use this hook - *will re-render **whenever any node changes**, including when a node is selected - *or moved. + * will re-render **whenever any node changes**, including when a node is selected + * or moved. * * @public * @returns An array of nodes diff --git a/packages/react/src/hooks/useNodesEdgesState.ts b/packages/react/src/hooks/useNodesEdgesState.ts index b9722d80..b5919e5e 100644 --- a/packages/react/src/hooks/useNodesEdgesState.ts +++ b/packages/react/src/hooks/useNodesEdgesState.ts @@ -5,8 +5,8 @@ import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; /** * This hook makes it easy to prototype a controlled flow where you manage the - *state of nodes and edges outside the `ReactFlowInstance`. You can think of it - *like React's `useState` hook with an additional helper callback. + * state of nodes and edges outside the `ReactFlowInstance`. You can think of it + * like React's `useState` hook with an additional helper callback. * * @public * @param initialNodes @@ -34,10 +34,10 @@ import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; *} *``` * - *@remarks This hook was created to make prototyping easier and our documentation - *examples clearer. Although it is OK to use this hook in production, in - *practice you may want to use a more sophisticated state management solution - *like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. + * @remarks This hook was created to make prototyping easier and our documentation + * examples clearer. Although it is OK to use this hook in production, in + * practice you may want to use a more sophisticated state management solution + * like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. * */ export function useNodesState( @@ -54,8 +54,8 @@ export function useNodesState( /** * This hook makes it easy to prototype a controlled flow where you manage the - *state of nodes and edges outside the `ReactFlowInstance`. You can think of it - *like React's `useState` hook with an additional helper callback. + * state of nodes and edges outside the `ReactFlowInstance`. You can think of it + * like React's `useState` hook with an additional helper callback. * * @public * @param initialEdges @@ -84,9 +84,9 @@ export function useNodesState( *``` * * @remarks This hook was created to make prototyping easier and our documentation - *examples clearer. Although it is OK to use this hook in production, in - *practice you may want to use a more sophisticated state management solution - *like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. + * examples clearer. Although it is OK to use this hook in production, in + * practice you may want to use a more sophisticated state management solution + * like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead. * */ export function useEdgesState( diff --git a/packages/react/src/hooks/useStore.ts b/packages/react/src/hooks/useStore.ts index e34e2c36..3b0a2778 100644 --- a/packages/react/src/hooks/useStore.ts +++ b/packages/react/src/hooks/useStore.ts @@ -10,8 +10,8 @@ const zustandErrorMessage = errorMessages['error001'](); /** * This hook can be used to subscribe to internal state changes of the React Flow - *component. The `useStore` hook is re-exported from the [Zustand](https://github.com/pmndrs/zustand) - *state management library, so you should check out their docs for more details. + * component. The `useStore` hook is re-exported from the [Zustand](https://github.com/pmndrs/zustand) + * state management library, so you should check out their docs for more details. * * @public * @param selector @@ -24,8 +24,8 @@ const zustandErrorMessage = errorMessages['error001'](); * ``` * * @remarks This hook should only be used if there is no other way to access the internal - *state. For many of the common use cases, there are dedicated hooks available - *such as {@link useReactFlow}, {@link useViewport}, etc. + * state. For many of the common use cases, there are dedicated hooks available + * such as {@link useReactFlow}, {@link useViewport}, etc. */ function useStore( selector: (state: ReactFlowState) => StateSlice, @@ -51,8 +51,8 @@ function useStore( * ``` * * @remarks This hook should only be used if there is no other way to access the internal - *state. For many of the common use cases, there are dedicated hooks available - *such as {@link useReactFlow}, {@link useViewport}, etc. + * state. For many of the common use cases, there are dedicated hooks available + * such as {@link useReactFlow}, {@link useViewport}, etc. */ function useStoreApi() { const store = useContext(StoreContext) as UseBoundStoreWithEqualityFn< diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index ce21e84f..1a6de7c2 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -19,6 +19,9 @@ import type { import { EdgeTypes, InternalNode, Node } from '.'; +/** + * @inline + */ export type EdgeLabelOptions = { label?: string | ReactNode; labelStyle?: CSSProperties; @@ -29,7 +32,8 @@ export type EdgeLabelOptions = { }; /** - * The Edge type is mainly used for the `edges` that get passed to the ReactFlow component + * An `Edge` is the complete description with everything React Flow needs + *to know in order to render it. * @public */ export type Edge< @@ -91,6 +95,12 @@ export type EdgeWrapperProps = { disableKeyboardA11y?: boolean; }; +/** + * Many properties on an [`Edge`](/api-reference/types/edge) are optional. When a new edge is created, + *the properties that are not provided will be filled in with the default values + *passed to the `defaultEdgeOptions` prop of the [``](/api-reference/react-flow#defaultedgeoptions) + *component. + */ export type DefaultEdgeOptions = DefaultEdgeOptionsBase; export type EdgeTextProps = SVGAttributes & @@ -100,8 +110,10 @@ export type EdgeTextProps = SVGAttributes & }; /** - * Custom edge component props + * When you implement a custom edge it is wrapped in a component that enables some + *basic functionality. The `EdgeProps` type is the props that are passed to this. * @public + * @expand */ export type EdgeProps = Pick< EdgeType, @@ -185,6 +197,13 @@ export type SimpleBezierEdgeProps = EdgeComponentProps; export type OnReconnect = (oldEdge: EdgeType, newConnection: Connection) => void; +/** + * If you want to render a custom component for connection lines, you can set the + *`connectionLineComponent` prop on the [``](/api-reference/react-flow#connection-connectionLineComponent) + *component. The `ConnectionLineComponentProps` are passed to your custom component. + * + * @public + */ export type ConnectionLineComponentProps = { connectionLineStyle?: CSSProperties; connectionLineType: ConnectionLineType; diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 48e5b2fe..249cf01b 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -64,12 +64,23 @@ export type OnSelectionChangeParams = { export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void; export type FitViewParams = FitViewParamsBase; + +/** + * When calling [`fitView`](/api-reference/types/react-flow-instance#fitview) these options + * can be used to customize the behaviour. For example, the `duration` option can be used to + * transform the viewport smoothly over a given amount of time. + * + * @public + */ export type FitViewOptions = FitViewOptionsBase; export type FitView = (fitViewOptions?: FitViewOptions) => Promise; export type OnInit = ( reactFlowInstance: ReactFlowInstance ) => void; +/** + * @inline + */ export type ViewportHelperFunctions = { /** * Zooms viewport in by 1.2. diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts index 992655a4..fbfa39ce 100644 --- a/packages/react/src/types/instance.ts +++ b/packages/react/src/types/instance.ts @@ -217,6 +217,14 @@ export type GeneralHelpers NodeConnection[]; }; +/** + * The `ReactFlowInstance` provides a collection of methods to query and manipulate + *the internal state of your flow. You can get an instance by using the + *[`useReactFlow`](/api-reference/hooks/use-react-flow) hook or attaching a listener to the + *[`onInit`](/api-reference/react-flow#event-oninit) event. + * + * @public + */ export type ReactFlowInstance = GeneralHelpers< NodeType, EdgeType diff --git a/packages/react/src/types/nodes.ts b/packages/react/src/types/nodes.ts index 0d3924e4..cfdefb13 100644 --- a/packages/react/src/types/nodes.ts +++ b/packages/react/src/types/nodes.ts @@ -4,7 +4,9 @@ import type { CoordinateExtent, NodeBase, OnError, NodeProps as NodePropsBase, I import { NodeTypes } from './general'; /** - * The node data structure that gets used for the nodes prop. + * The `Node` type represents everything React Flow needs to know about a given node. + * Many of these properties can be manipulated both by React Flow or by you, but + * some such as `width` and `height` should be considered read-only. * @public */ export type Node< @@ -18,9 +20,10 @@ export type Node< }; /** - * The node data structure that gets used for internal nodes. - * There are some data structures added under node.internal - * that are needed for tracking some properties + * The `InternalNode` type is identical to the base [`Node`](/api-references/types/node) + * type but is extended with some additional properties used internall by React + * Flow. Some functions and callbacks that return nodes may return an `InternalNode`. + * * @public */ export type InternalNode = InternalNodeBase; @@ -60,4 +63,31 @@ export type BuiltInNode = | Node<{ label: string }, 'input' | 'output' | 'default'> | Node, 'group'>; +/** + * When you implement a [custom node](/learn/customization/custom-nodes) it is + * wrapped in a component that enables basic functionality like selection and + * dragging. Your custom node receives `NodeProps` as props. + * + * @public + * @example + * ```tsx + *import { useState } from 'react'; + *import { NodeProps, Node } from '@xyflow/react'; + * + *export type CounterNode = Node<{ initialCount?: number }, 'counter'>; + * + *export default function CounterNode(props: NodeProps) { + * const [count, setCount] = useState(props.data?.initialCount ?? 0); + * + * return ( + *
+ *

Count: {count}

+ * + *
+ * ); + *} + *``` + */ export type NodeProps = NodePropsBase; diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index 6ac2e3c5..e21bdfb6 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -4,9 +4,10 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '../types'; /** - * Test whether an object is useable as an [`Node`](/api-reference/types/node). In TypeScript - *this is a type guard that will narrow the type of whatever you pass in to - *[`Node`](/api-reference/types/node) if it returns `true`. + * Test whether an object is useable as an [`Node`](/api-reference/types/node). + * In TypeScript this is a type guard that will narrow the type of whatever you pass in to + * [`Node`](/api-reference/types/node) if it returns `true`. + * * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true * @param element - The element to test @@ -25,9 +26,10 @@ export const isNode = (element: unknown): element isNodeBase(element); /** - * Test whether an object is useable as an [`Edge`](/api-reference/types/edge). In TypeScript - *this is a type guard that will narrow the type of whatever you pass in to - *[`Edge`](/api-reference/types/edge) if it returns `true`. + * Test whether an object is useable as an [`Edge`](/api-reference/types/edge). + * In TypeScript this is a type guard that will narrow the type of whatever you pass in to + * [`Edge`](/api-reference/types/edge) if it returns `true`. + * * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true * @param element - The element to test diff --git a/packages/svelte/src/lib/types/edges.ts b/packages/svelte/src/lib/types/edges.ts index de1def91..b2f6ba7e 100644 --- a/packages/svelte/src/lib/types/edges.ts +++ b/packages/svelte/src/lib/types/edges.ts @@ -11,7 +11,9 @@ import type { import type { Node } from '$lib/types'; /** - * The Edge type is mainly used for the `edges` that get passed to the SvelteFlow component. + * An `Edge` is the complete description with everything React Flow needs + *to know in order to render it. + * @public */ export type Edge< EdgeData extends Record = Record, diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index abe7c8f2..9f52b5a3 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -103,6 +103,12 @@ export type EdgeMarker = { export type EdgeMarkerType = string | EdgeMarker; +/** + * Edges may optionally have a marker on either end. The MarkerType type enumerates + * the options available to you when configuring a given marker. + * + * @public + */ export enum MarkerType { Arrow = 'arrow', ArrowClosed = 'arrowclosed', diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 485bb4f5..8ac3f9e9 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -28,8 +28,8 @@ export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => Promise boolean; +/** + * @inline + */ export type FitViewParamsBase = { nodes: Map>; width: number; @@ -75,6 +91,9 @@ export type FitViewParamsBase = { maxZoom: number; }; +/** + * @inline + */ export type FitViewOptionsBase = { padding?: number; includeHiddenNodes?: boolean; @@ -84,6 +103,17 @@ export type FitViewOptionsBase = { nodes?: (NodeType | { id: string })[]; }; +/** + * Internally, React Flow maintains a coordinate system that is independent of the + * rest of the page. The `Viewport` type tells you where in that system your flow + * is currently being display at and how zoomed in or out it is. + * + * @public + * @remarks A `Transform` has the same properties as the viewport, but they represent + * different things. Make sure you don't get them muddled up or things will start + * to look weird! + * + */ export type Viewport = { x: number; y: number; @@ -94,12 +124,23 @@ export type KeyCode = string | Array; export type SnapGrid = [number, number]; +/** + * This enum is used to set the different modes of panning the viewport when the + * user scrolls. The `Free` mode allows the user to pan in any direction by scrolling + * with a device like a trackpad. The `Vertical` and `Horizontal` modes restrict + * scroll panning to only the vertical or horizontal axis, respectively. + * + * @public + */ export enum PanOnScrollMode { Free = 'free', Vertical = 'vertical', Horizontal = 'horizontal', } +/** + * @inline + */ export type ViewportHelperFunctionOptions = { duration?: number; }; @@ -120,6 +161,14 @@ export type D3ZoomHandler = (this: Element, event: any, d: unknown) => void; export type UpdateNodeInternals = (nodeId: string | string[]) => void; +/** + * This type is mostly used to help position things on top of the flow viewport. For + * example both the [``](/api-reference/components/minimap) and + * [``](/api-reference/components/controls) components take a `position` + * prop of this type. + * + * @public + */ export type PanelPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; export type ProOptions = { @@ -183,7 +232,8 @@ export type ConnectionInProgress = NodeType & z: number; /** * Holds a reference to the original node object provided by the user. - * Used as an optimization to avoid certain operations. + * Used as an optimization to avoid certain operations. */ userNode: NodeType; handleBounds?: NodeHandleBounds; @@ -89,7 +90,7 @@ export type InternalNodeBase = NodeType & }; /** - * The node data structure that gets used for the nodes prop. + * The node data structure that gets used for the custom nodes props. * * @public */ @@ -141,10 +142,22 @@ export type NodeDragItem = { expandParent?: boolean; }; +/** + * The origin of a Node determines how it is placed relative to its own coordinates. + * `[0, 0]` places it at the top left corner, `[0.5, 0.5]` right in the center and + * `[1, 1]` at the bottom right of its position. + * + * @public + */ export type NodeOrigin = [number, number]; export type OnSelectionDrag = (event: MouseEvent, nodes: NodeBase[]) => void; +/** + * Type for the handles of a node + * + * @public + */ export type NodeHandle = Omit, 'nodeId'>; export type Align = 'center' | 'start' | 'end'; diff --git a/packages/system/src/types/utils.ts b/packages/system/src/types/utils.ts index 61d55698..274bfe55 100644 --- a/packages/system/src/types/utils.ts +++ b/packages/system/src/types/utils.ts @@ -1,3 +1,10 @@ +/** + * While [`PanelPosition`](/api-reference/types/panel-position) can be used to place a + * component in the corners of a container, the `Position` enum is less precise and used + * primarily in relation to edges and handles. + * + * @public + */ export enum Position { Left = 'left', Top = 'top', @@ -12,6 +19,11 @@ export const oppositePosition = { [Position.Bottom]: Position.Top, }; +/** + * All positions are stored in an object with x and y coordinates. + * + * @public + */ export type XYPosition = { x: number; y: number; @@ -35,12 +47,12 @@ export type Transform = [number, number, number]; /** * A coordinate extent represents two points in a coordinate system: one in the top - *left corner and one in the bottom right corner. It is used to represent the - *bounds of nodes in the flow or the bounds of the viewport. + * left corner and one in the bottom right corner. It is used to represent the + * bounds of nodes in the flow or the bounds of the viewport. * * @public * * @remarks Props that expect a `CoordinateExtent` usually default to `[[-∞, -∞], [+∞, +∞]]` - *to represent an unbounded extent. + * to represent an unbounded extent. */ export type CoordinateExtent = [[number, number], [number, number]]; From a541799654799cd46bd3f93eb0aa879708279f3e Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 12:26:22 +0100 Subject: [PATCH 014/157] chore(types): add tsdocs --- .../additional-components/MiniMap/MiniMap.tsx | 12 +++---- .../NodeToolbar/NodeToolbar.tsx | 2 +- packages/react/src/types/edges.ts | 13 ++++--- packages/react/src/types/general.ts | 34 +++++++++++++++++++ packages/react/src/types/instance.ts | 9 +++-- packages/react/src/types/nodes.ts | 20 ++++++++--- packages/react/src/utils/changes.ts | 13 ++++--- 7 files changed, 77 insertions(+), 26 deletions(-) diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index be6dc453..c7f1fdce 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -113,16 +113,16 @@ function MiniMapComponent({ const onSvgClick = onClick ? (event: MouseEvent) => { - const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; - onClick(event, { x, y }); - } + const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; + onClick(event, { x, y }); + } : undefined; const onSvgNodeClick = onNodeClick ? useCallback((event: MouseEvent, nodeId: string) => { - const node = store.getState().nodeLookup.get(nodeId)!; - onNodeClick(event, node); - }, []) + const node = store.getState().nodeLookup.get(nodeId)!; + onNodeClick(event, node); + }, []) : undefined; return ( diff --git a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx index 0248b394..3fddceaa 100644 --- a/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx +++ b/packages/react/src/additional-components/NodeToolbar/NodeToolbar.tsx @@ -109,7 +109,7 @@ export function NodeToolbar({ const isActive = typeof isVisible === 'boolean' ? isVisible - : nodes.size === 1 && nodes.values().next().value.selected && selectedNodesCount === 1; + : nodes.size === 1 && nodes.values().next().value?.selected && selectedNodesCount === 1; if (!isActive || !nodes.size) { return null; diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 1a6de7c2..e25fdeb8 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -33,7 +33,7 @@ export type EdgeLabelOptions = { /** * An `Edge` is the complete description with everything React Flow needs - *to know in order to render it. + * to know in order to render it. * @public */ export type Edge< @@ -97,9 +97,8 @@ export type EdgeWrapperProps = { /** * Many properties on an [`Edge`](/api-reference/types/edge) are optional. When a new edge is created, - *the properties that are not provided will be filled in with the default values - *passed to the `defaultEdgeOptions` prop of the [``](/api-reference/react-flow#defaultedgeoptions) - *component. + * the properties that are not provided will be filled in with the default values + * passed to the `defaultEdgeOptions` prop of the [``](/api-reference/react-flow#defaultedgeoptions) component. */ export type DefaultEdgeOptions = DefaultEdgeOptionsBase; @@ -111,7 +110,7 @@ export type EdgeTextProps = SVGAttributes & /** * When you implement a custom edge it is wrapped in a component that enables some - *basic functionality. The `EdgeProps` type is the props that are passed to this. + * basic functionality. The `EdgeProps` type is the props that are passed to this. * @public * @expand */ @@ -199,8 +198,8 @@ export type OnReconnect = (oldEdge: EdgeType, newC /** * If you want to render a custom component for connection lines, you can set the - *`connectionLineComponent` prop on the [``](/api-reference/react-flow#connection-connectionLineComponent) - *component. The `ConnectionLineComponentProps` are passed to your custom component. + * `connectionLineComponent` prop on the [``](/api-reference/react-flow#connection-connectionLineComponent) + * component. The `ConnectionLineComponentProps` are passed to your custom component. * * @public */ diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 249cf01b..913ec634 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -18,11 +18,44 @@ import { import type { Node, Edge, ReactFlowInstance, EdgeProps, NodeProps } from '.'; +/** + * This type can be used to type the `onNodesChange` function with a custom node type. + * + * @public + * + * @example + * + * ```ts + * const onNodesChange: OnNodesChange = useCallback((changes) => { + * setNodes((nodes) => applyNodeChanges(nodes, changes)); + * },[]); + * ``` + */ export type OnNodesChange = (changes: NodeChange[]) => void; + +/** + * This type can be used to type the `onEdgesChange` function with a custom edge type. + * + * @public + * + * @example + * + * ```ts + * const onEdgesChange: OnEdgesChange = useCallback((changes) => { + * setEdges((edges) => applyEdgeChanges(edges, changes)); + * },[]); + * ``` + */ export type OnEdgesChange = (changes: EdgeChange[]) => void; export type OnNodesDelete = (nodes: NodeType[]) => void; export type OnEdgesDelete = (edges: EdgeType[]) => void; + +/** + * This type can be used to type the `onDelete` function with a custom node and edge type. + * + * @public + */ export type OnDelete = (params: { nodes: NodeType[]; edges: EdgeType[]; @@ -39,6 +72,7 @@ export type NodeTypes = Record< } > >; + export type EdgeTypes = Record< string, ComponentType< diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts index fbfa39ce..85d66651 100644 --- a/packages/react/src/types/instance.ts +++ b/packages/react/src/types/instance.ts @@ -13,6 +13,9 @@ export type DeleteElementsOptions = { edges?: (Edge | { id: Edge['id'] })[]; }; +/** + * @inline + */ export type GeneralHelpers = { /** * Returns nodes. @@ -219,9 +222,9 @@ export type GeneralHelpers = { nodeClickDistance?: number; }; +/** + * The `BuiltInNode` type represents the built-in node types that are available in React Flow. + * You can use this type to extend your custom node type if you still want ot use the built-in ones. + * + * @public + * @example + * ```ts + * type CustomNode = Node<{ value: number }, 'custom'>; + * type MyAppNode = CustomNode | BuiltInNode; + * ``` + */ export type BuiltInNode = | Node<{ label: string }, 'input' | 'output' | 'default'> | Node, 'group'>; diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index ea0a9140..0bc30e46 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -147,8 +147,6 @@ function applyChange(change: any, element: any): any { /** * Drop in function that applies node changes to an array of nodes. * @public - * @remarks Various events on the component can produce an {@link NodeChange} that describes how to update the edges of your flow in some way. - *If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. * @param changes - Array of changes to apply * @param nodes - Array of nodes to apply the changes to * @returns Array of updated nodes @@ -172,6 +170,10 @@ function applyChange(change: any, element: any): any { * ); *} *``` + * @remarks Various events on the component can produce an {@link NodeChange} + * that describes how to update the edges of your flow in some way. + * If you don't need any custom behaviour, this util can be used to take an array + * of these changes and apply them to your edges. */ export function applyNodeChanges( changes: NodeChange[], @@ -183,13 +185,10 @@ export function applyNodeChanges( /** * Drop in function that applies edge changes to an array of edges. * @public - * @remarks Various events on the component can produce an {@link EdgeChange} that describes how to update the edges of your flow in some way. - *If you don't need any custom behaviour, this util can be used to take an array of these changes and apply them to your edges. * @param changes - Array of changes to apply * @param edges - Array of edge to apply the changes to * @returns Array of updated edges * @example - * * ```tsx *import { useState, useCallback } from 'react'; *import { ReactFlow, applyEdgeChanges } from '@xyflow/react'; @@ -209,6 +208,10 @@ export function applyNodeChanges( * ); *} *``` + * @remarks Various events on the component can produce an {@link EdgeChange} + * that describes how to update the edges of your flow in some way. + * If you don't need any custom behaviour, this util can be used to take an array + * of these changes and apply them to your edges. */ export function applyEdgeChanges( changes: EdgeChange[], From a7b141a9170042f579a4cb215f321044c4bd0ef4 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 12:51:52 +0100 Subject: [PATCH 015/157] chore(screenToflowPosition): use correct defaults add snapGrid --- packages/react/src/hooks/useViewportHelper.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/react/src/hooks/useViewportHelper.ts b/packages/react/src/hooks/useViewportHelper.ts index 5e7e6cfa..9a773d14 100644 --- a/packages/react/src/hooks/useViewportHelper.ts +++ b/packages/react/src/hooks/useViewportHelper.ts @@ -7,6 +7,7 @@ import { type XYPosition, rendererPointToPoint, getDimensions, + SnapGrid, } from '@xyflow/system'; import { useStoreApi } from '../hooks/useStore'; @@ -119,21 +120,25 @@ const useViewportHelper = (): ViewportHelperFunctions => { return Promise.resolve(true); }, - screenToFlowPosition: (clientPosition: XYPosition, options: { snapToGrid: boolean } = { snapToGrid: true }) => { - const { transform, snapGrid, domNode } = store.getState(); + screenToFlowPosition: ( + clientPosition: XYPosition, + options: { snapToGrid?: boolean; snapGrid?: SnapGrid } = {} + ) => { + const { transform, snapGrid, snapToGrid, domNode } = store.getState(); if (!domNode) { return clientPosition; } const { x: domX, y: domY } = domNode.getBoundingClientRect(); - const correctedPosition = { x: clientPosition.x - domX, y: clientPosition.y - domY, }; + const _snapGrid = options.snapGrid ?? snapGrid; + const _snapToGrid = options.snapToGrid ?? snapToGrid; - return pointToRendererPoint(correctedPosition, transform, options.snapToGrid, snapGrid); + return pointToRendererPoint(correctedPosition, transform, _snapToGrid, _snapGrid); }, flowToScreenPosition: (flowPosition: XYPosition) => { const { transform, domNode } = store.getState(); From 4d3f19e88b984ce6743970560d7367d174500f32 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 13:06:00 +0100 Subject: [PATCH 016/157] chore(changeset): add --- .changeset/quick-cobras-report.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/quick-cobras-report.md diff --git a/.changeset/quick-cobras-report.md b/.changeset/quick-cobras-report.md new file mode 100644 index 00000000..68ed7250 --- /dev/null +++ b/.changeset/quick-cobras-report.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Add snapGrid option to screenToFlowPosition and set snapToGrid to false From 4947029cd6cda0f695e1fb4815e4030adb232234 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 13:43:13 +0100 Subject: [PATCH 017/157] chore(changeset): add --- .changeset/serious-ducks-care.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/serious-ducks-care.md diff --git a/.changeset/serious-ducks-care.md b/.changeset/serious-ducks-care.md new file mode 100644 index 00000000..77c69a3d --- /dev/null +++ b/.changeset/serious-ducks-care.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Make it possible to stop autoPanOnDrag by setting it to false From 4c62f19b3afac4b3db84b14e2c36f8c9e0a96116 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 13:58:55 +0100 Subject: [PATCH 018/157] chore(changeset): add --- .changeset/sour-jobs-fold.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sour-jobs-fold.md diff --git a/.changeset/sour-jobs-fold.md b/.changeset/sour-jobs-fold.md new file mode 100644 index 00000000..f21dc567 --- /dev/null +++ b/.changeset/sour-jobs-fold.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Prevent viewport shift after using Tab From 1344ccad39a8e05286c37fed1eff50cbc80f6f86 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 14:18:14 +0100 Subject: [PATCH 019/157] chore(connection-line): pass generic --- .../src/components/ConnectionLine/index.tsx | 19 +++++++++++++++---- .../react/src/container/GraphView/index.tsx | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/react/src/components/ConnectionLine/index.tsx b/packages/react/src/components/ConnectionLine/index.tsx index 86479900..c179fae2 100644 --- a/packages/react/src/components/ConnectionLine/index.tsx +++ b/packages/react/src/components/ConnectionLine/index.tsx @@ -29,7 +29,12 @@ const selector = (s: ReactFlowState) => ({ height: s.height, }); -export function ConnectionLineWrapper({ containerStyle, style, type, component }: ConnectionLineWrapperProps) { +export function ConnectionLineWrapper({ + containerStyle, + style, + type, + component, +}: ConnectionLineWrapperProps) { const { nodesConnectable, width, height, isValid, inProgress } = useStore(selector, shallow); const renderConnection = !!(width && nodesConnectable && inProgress); @@ -45,7 +50,7 @@ export function ConnectionLineWrapper({ containerS className="react-flow__connectionline react-flow__container" > - + style={style} type={type} CustomComponent={component} isValid={isValid} /> ); @@ -58,8 +63,14 @@ type ConnectionLineProps = { isValid: boolean | null; }; -const ConnectionLine = ({ style, type = ConnectionLineType.Bezier, CustomComponent, isValid }: ConnectionLineProps) => { - const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection(); +const ConnectionLine = ({ + style, + type = ConnectionLineType.Bezier, + CustomComponent, + isValid, +}: ConnectionLineProps) => { + const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = + useConnection(); if (!inProgress) { return; diff --git a/packages/react/src/container/GraphView/index.tsx b/packages/react/src/container/GraphView/index.tsx index 7356c8f4..fd0296f1 100644 --- a/packages/react/src/container/GraphView/index.tsx +++ b/packages/react/src/container/GraphView/index.tsx @@ -170,7 +170,7 @@ function GraphViewComponent - style={connectionLineStyle} type={connectionLineType} component={connectionLineComponent} From b90b5c0500ef995d841bbdc05222ae294a5343b5 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 14:20:28 +0100 Subject: [PATCH 020/157] chore(changeset): add --- .changeset/stale-kings-own.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/stale-kings-own.md diff --git a/.changeset/stale-kings-own.md b/.changeset/stale-kings-own.md new file mode 100644 index 00000000..051d0770 --- /dev/null +++ b/.changeset/stale-kings-own.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Pass NodeType generic to connection line component From 0a428c7e1de8c4a0e3564ab2f95caf0078909206 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 14:21:31 +0100 Subject: [PATCH 021/157] chore(changeset): cleanup --- .changeset/happy-hats-lay.md | 2 +- .changeset/stale-kings-own.md | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 .changeset/stale-kings-own.md diff --git a/.changeset/happy-hats-lay.md b/.changeset/happy-hats-lay.md index 3a312bc3..eb58de7d 100644 --- a/.changeset/happy-hats-lay.md +++ b/.changeset/happy-hats-lay.md @@ -1,5 +1,5 @@ --- -'@xyflow/react': minor +'@xyflow/react': patch --- Pass `NodeType` type argument from `ReactFlowProps` to `connectionLineComponent` property. diff --git a/.changeset/stale-kings-own.md b/.changeset/stale-kings-own.md deleted file mode 100644 index 051d0770..00000000 --- a/.changeset/stale-kings-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Pass NodeType generic to connection line component From c3dc6d3851749925d63012c331b77deacea32f49 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 14:29:20 +0100 Subject: [PATCH 022/157] chore(tsdocs): cleanup --- packages/system/src/utils/graph.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 1bb318d4..b2b1e6e5 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -55,7 +55,7 @@ export const isInternalNodeBase = = { /** * Returns the bounding box that contains all the given nodes in an array. This can - *be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds) - *to calculate the correct transform to fit the given nodes in a viewport. + * be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds) + * to calculate the correct transform to fit the given nodes in a viewport. * @public * @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport. * @param nodes - Nodes to calculate the bounds for @@ -212,8 +212,8 @@ export const getNodesBounds = ( currentNode = isId ? params.nodeLookup.get(nodeOrId) : !isInternalNodeBase(nodeOrId) - ? params.nodeLookup.get(nodeOrId.id) - : nodeOrId; + ? params.nodeLookup.get(nodeOrId.id) + : nodeOrId; } const nodeBox = currentNode ? nodeToBox(currentNode, params.nodeOrigin) : { x: 0, y: 0, x2: 0, y2: 0 }; @@ -296,7 +296,8 @@ export const getNodesInside = ( }; /** - * This utility filters an array of edges, keeping only those where either the source or target node is present in the given array of nodes. + * This utility filters an array of edges, keeping only those where either the source or target + * node is present in the given array of nodes. * @public * @param nodes - Nodes you want to get the connected edges for * @param edges - All edges @@ -459,9 +460,9 @@ export async function getElementsToRemove; }): Promise<{ - nodes: NodeType[]; - edges: EdgeType[]; - }> { + nodes: NodeType[]; + edges: EdgeType[]; +}> { const nodeIds = new Set(nodesToRemove.map((node) => node.id)); const matchingNodes: NodeType[] = []; From 0b06491ef9c139d13c8ea73a26c1b18070fe0381 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 14:42:12 +0100 Subject: [PATCH 023/157] chore(tsdocs): cleanup --- .../additional-components/Controls/types.ts | 6 +++++ .../additional-components/MiniMap/types.ts | 4 ++++ .../NodeResizer/types.ts | 9 ++++++++ .../NodeToolbar/types.ts | 3 +++ .../react/src/components/Handle/index.tsx | 12 ++++++---- packages/react/src/components/Panel/index.tsx | 23 +++++++++++-------- packages/react/src/types/edges.ts | 7 ++++++ packages/system/src/types/edges.ts | 3 +++ packages/system/src/xyresizer/types.ts | 15 ++++++++++++ 9 files changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/react/src/additional-components/Controls/types.ts b/packages/react/src/additional-components/Controls/types.ts index c36275d9..bccd1117 100644 --- a/packages/react/src/additional-components/Controls/types.ts +++ b/packages/react/src/additional-components/Controls/types.ts @@ -3,6 +3,9 @@ import type { PanelPosition } from '@xyflow/system'; import type { FitViewOptions } from '../../types'; +/** + * @expand + */ export type ControlProps = { /** Show button for zoom in/out */ showZoom?: boolean; @@ -35,4 +38,7 @@ export type ControlProps = { orientation?: 'horizontal' | 'vertical'; }; +/** + * @expand + */ export type ControlButtonProps = ButtonHTMLAttributes; diff --git a/packages/react/src/additional-components/MiniMap/types.ts b/packages/react/src/additional-components/MiniMap/types.ts index 351395f9..8416f835 100644 --- a/packages/react/src/additional-components/MiniMap/types.ts +++ b/packages/react/src/additional-components/MiniMap/types.ts @@ -6,6 +6,9 @@ import type { Node } from '../../types'; export type GetMiniMapNodeAttribute = (node: NodeType) => string; +/** + * @expand + */ export type MiniMapProps = Omit, 'onClick'> & { /** Color of nodes on minimap */ nodeColor?: string | GetMiniMapNodeAttribute; @@ -62,6 +65,7 @@ export type MiniMapNodes = Pick< * The props that are passed to the MiniMapNode component * * @public + * @expand */ export type MiniMapNodeProps = { id: string; diff --git a/packages/react/src/additional-components/NodeResizer/types.ts b/packages/react/src/additional-components/NodeResizer/types.ts index 2d1a7c15..1295440f 100644 --- a/packages/react/src/additional-components/NodeResizer/types.ts +++ b/packages/react/src/additional-components/NodeResizer/types.ts @@ -9,6 +9,9 @@ import type { OnResizeEnd, } from '@xyflow/system'; +/** + * @expand + */ export type NodeResizerProps = { /** * Id of the node it is resizing @@ -47,6 +50,9 @@ export type NodeResizerProps = { onResizeEnd?: OnResizeEnd; }; +/** + * @expand + */ export type ResizeControlProps = Pick< NodeResizerProps, | 'nodeId' @@ -77,6 +83,9 @@ export type ResizeControlProps = Pick< children?: ReactNode; }; +/** + * @expand + */ export type ResizeControlLineProps = ResizeControlProps & { position?: ControlLinePosition; }; diff --git a/packages/react/src/additional-components/NodeToolbar/types.ts b/packages/react/src/additional-components/NodeToolbar/types.ts index 00bec37c..91a717da 100644 --- a/packages/react/src/additional-components/NodeToolbar/types.ts +++ b/packages/react/src/additional-components/NodeToolbar/types.ts @@ -1,6 +1,9 @@ import type { HTMLAttributes } from 'react'; import type { Position, Align } from '@xyflow/system'; +/** + * @expand + */ export type NodeToolbarProps = HTMLAttributes & { /** Id of the node, or array of ids the toolbar should be displayed at */ nodeId?: string | string[]; diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index 72e7ad21..df7b428b 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -28,10 +28,14 @@ import { useNodeId } from '../../contexts/NodeIdContext'; import { type ReactFlowState } from '../../types'; import { fixedForwardRef } from '../../utils'; -export interface HandleProps extends HandlePropsSystem, Omit, 'id'> { - /** Callback called when connection is made */ - onConnect?: OnConnect; -} +/** + * @expand + */ +export type HandleProps = HandlePropsSystem & + Omit, 'id'> & { + /** Callback called when connection is made */ + onConnect?: OnConnect; + }; const selector = (s: ReactFlowState) => ({ connectOnClick: s.connectOnClick, diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index 461cc1ba..8d854b91 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -5,6 +5,19 @@ import type { PanelPosition } from '@xyflow/system'; import { useStore } from '../../hooks/useStore'; import type { ReactFlowState } from '../../types'; +/** + * @expand + */ +export type PanelProps = HTMLAttributes & { + /** + * The position of the panel + */ + position?: PanelPosition; + children: ReactNode; +}; + +const selector = (s: ReactFlowState) => (s.userSelectionActive ? 'none' : 'all'); + /** * The `` component helps you position content above the viewport. * It is used internally by the [``](/api-reference/components/minimap) @@ -30,16 +43,6 @@ import type { ReactFlowState } from '../../types'; *} *``` */ -export type PanelProps = HTMLAttributes & { - /** - * The position of the panel - */ - position?: PanelPosition; - children: ReactNode; -}; - -const selector = (s: ReactFlowState) => (s.userSelectionActive ? 'none' : 'all'); - export const Panel = forwardRef( ({ position = 'top-left', children, className, style, ...rest }, ref) => { const pointerEvents = useStore(selector); diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index e25fdeb8..4d1e3f04 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -132,6 +132,7 @@ export type EdgeProps = Pick< /** * BaseEdge component props * @public + * @expand */ export type BaseEdgeProps = Omit, 'd'> & EdgeLabelOptions & { @@ -148,6 +149,7 @@ export type BaseEdgeProps = Omit, 'd'> & /** * Helper type for edge components that get exported by the library * @public + * @expand */ export type EdgeComponentProps = EdgePosition & EdgeLabelOptions & { @@ -167,30 +169,35 @@ export type EdgeComponentWithPathOptions = EdgeComponentProps & { /** * BezierEdge component props * @public + * @expand */ export type BezierEdgeProps = EdgeComponentWithPathOptions; /** * SmoothStepEdge component props * @public + * @expand */ export type SmoothStepEdgeProps = EdgeComponentWithPathOptions; /** * StepEdge component props * @public + * @expand */ export type StepEdgeProps = EdgeComponentWithPathOptions; /** * StraightEdge component props * @public + * @expand */ export type StraightEdgeProps = Omit; /** * SimpleBezier component props * @public + * @expand */ export type SimpleBezierEdgeProps = EdgeComponentProps; diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index 9f52b5a3..76382e73 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -118,6 +118,9 @@ export type MarkerProps = EdgeMarker & { id: string; }; +/** + * @inline + */ export type EdgePosition = { sourceX: number; sourceY: number; diff --git a/packages/system/src/xyresizer/types.ts b/packages/system/src/xyresizer/types.ts index 99480512..34cad9e8 100644 --- a/packages/system/src/xyresizer/types.ts +++ b/packages/system/src/xyresizer/types.ts @@ -11,10 +11,25 @@ export type ResizeParamsWithDirection = ResizeParams & { direction: number[]; }; +/** + * Used to determine the control line position of the NodeResizer + * + * @public + */ export type ControlLinePosition = 'top' | 'bottom' | 'left' | 'right'; +/** + * Used to determine the control position of the NodeResizer + * + * @public + */ export type ControlPosition = ControlLinePosition | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; +/** + * Used to determine the variant of the resize control + * + * @public + */ export enum ResizeControlVariant { Line = 'line', Handle = 'handle', From f51f80db412bf835fe3fe95853a154fe1d02df22 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 16:31:16 +0100 Subject: [PATCH 024/157] chore(tsdocs): cleanup --- packages/react/package.json | 2 +- packages/system/package.json | 2 +- pnpm-lock.yaml | 48 ------------------------------ tooling/eslint-config/package.json | 1 - tooling/eslint-config/src/index.js | 4 +-- 5 files changed, 3 insertions(+), 54 deletions(-) diff --git a/packages/react/package.json b/packages/react/package.json index af284012..1cdf428c 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -57,7 +57,7 @@ "build": "rollup --config node:@xyflow/rollup-config --environment NODE_ENV:production && npm run css", "css": "postcss src/styles/{base,style}.css --config ./../../tooling/postcss-config/ --dir dist ", "css-watch": "pnpm css --watch", - "lint": "eslint --ext .js,.jsx,.ts,.tsx src --fix", + "lint": "eslint --ext .js,.jsx,.ts,.tsx src", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/packages/system/package.json b/packages/system/package.json index dfb81e1c..c7b1ee03 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -46,7 +46,7 @@ "scripts": { "dev": "concurrently \"rollup --config node:@xyflow/rollup-config --watch\"", "build": "rollup --config node:@xyflow/rollup-config --environment NODE_ENV:production", - "lint": "eslint --ext .js,.ts src --fix", + "lint": "eslint --ext .js,.ts src", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ae9a41c..22541966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,9 +428,6 @@ importers: tooling/eslint-config: devDependencies: - '@stylistic/eslint-plugin': - specifier: ^3.1.0 - version: 3.1.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/eslint-plugin': specifier: ^8.23.0 version: 8.23.0(@typescript-eslint/parser@8.23.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) @@ -1709,12 +1706,6 @@ packages: resolution: {integrity: sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==} engines: {node: '>=18'} - '@stylistic/eslint-plugin@3.1.0': - resolution: {integrity: sha512-pA6VOrOqk0+S8toJYhQGv2MWpQQR0QpeUo9AhNkC49Y26nxBQ/nH1rta9bUU1rPw2fJ1zZEMV5oCX5AazT7J2g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: '>=8.40.0' - '@svelte-put/shortcut@3.1.1': resolution: {integrity: sha512-2L5EYTZXiaKvbEelVkg5znxqvfZGZai3m97+cAiUBhLZwXnGtviTDpHxOoZBsqz41szlfRMcamW/8o0+fbW3ZQ==} peerDependencies: @@ -2226,11 +2217,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} - engines: {node: '>=0.4.0'} - hasBin: true - aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -3304,10 +3290,6 @@ packages: esm-env@1.0.0: resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4794,10 +4776,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} @@ -7981,18 +7959,6 @@ snapshots: '@sindresorhus/merge-streams@1.0.0': {} - '@stylistic/eslint-plugin@3.1.0(eslint@8.57.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/utils': 8.23.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.0 - estraverse: 5.3.0 - picomatch: 4.0.2 - transitivePeerDependencies: - - supports-color - - typescript - '@svelte-put/shortcut@3.1.1(svelte@4.2.12)': dependencies: svelte: 4.2.12 @@ -8647,18 +8613,12 @@ snapshots: dependencies: acorn: 8.10.0 - acorn-jsx@5.3.2(acorn@8.14.0): - dependencies: - acorn: 8.14.0 - acorn@8.10.0: {} acorn@8.11.2: {} acorn@8.11.3: {} - acorn@8.14.0: {} - aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -10297,12 +10257,6 @@ snapshots: esm-env@1.0.0: {} - espree@10.3.0: - dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) - eslint-visitor-keys: 4.2.0 - espree@9.6.1: dependencies: acorn: 8.10.0 @@ -12007,8 +11961,6 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} - pify@2.3.0: {} pify@4.0.1: {} diff --git a/tooling/eslint-config/package.json b/tooling/eslint-config/package.json index 2c664276..d4aa78ee 100644 --- a/tooling/eslint-config/package.json +++ b/tooling/eslint-config/package.json @@ -5,7 +5,6 @@ "license": "MIT", "main": "src/index.js", "devDependencies": { - "@stylistic/eslint-plugin": "^3.1.0", "@typescript-eslint/eslint-plugin": "^8.23.0", "@typescript-eslint/parser": "^8.23.0", "eslint-config-prettier": "^10.0.1", diff --git a/tooling/eslint-config/src/index.js b/tooling/eslint-config/src/index.js index 7bd69b5a..f2ce34a0 100644 --- a/tooling/eslint-config/src/index.js +++ b/tooling/eslint-config/src/index.js @@ -13,7 +13,7 @@ module.exports = { 'turbo', 'prettier', ], - plugins: ['react', '@typescript-eslint', '@stylistic'], + plugins: ['react', '@typescript-eslint'], parserOptions: { ecmaFeatures: { jsx: true, @@ -28,7 +28,5 @@ module.exports = { }, rules: { '@typescript-eslint/no-non-null-assertion': 'off', - '@stylistic/indent': ['error', 2], - '@stylistic/multiline-comment-style': ['error', 'starred-block'], }, }; From 6c121d427fea9a11e86a85f95d2c12ba8af34919 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 16:33:33 +0100 Subject: [PATCH 025/157] chore(changeset): add --- .changeset/brown-apples-deliver.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/brown-apples-deliver.md diff --git a/.changeset/brown-apples-deliver.md b/.changeset/brown-apples-deliver.md new file mode 100644 index 00000000..cf1754ad --- /dev/null +++ b/.changeset/brown-apples-deliver.md @@ -0,0 +1,7 @@ +--- +'@xyflow/react': patch +'@xyflow/svelte': patch +'@xyflow/system': patch +--- + +Add more TSDocs to components, hooks, utils funcs and types From 41176229700551000b07a53ef560f65b35825c83 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 12 Feb 2025 16:58:52 +0100 Subject: [PATCH 026/157] chore(react): cleanup --- packages/react/src/utils/general.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index e21bdfb6..f3cc26ea 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -47,7 +47,7 @@ export const isNode = (element: unknown): element export const isEdge = (element: unknown): element is EdgeType => isEdgeBase(element); -// eslint-disable-next-line @typescript-eslint/ban-types +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export function fixedForwardRef( render: (props: P, ref: Ref) => JSX.Element ): (props: P & RefAttributes) => JSX.Element { From ebffcb79a4822c6d88e04616845035f5d568f649 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Feb 2025 16:00:10 +0000 Subject: [PATCH 027/157] chore(packages): bump --- .changeset/brown-apples-deliver.md | 7 ------- .changeset/cyan-pianos-lie.md | 5 ----- .changeset/happy-hats-lay.md | 5 ----- .changeset/polite-hounds-yawn.md | 5 ----- .changeset/quick-cobras-report.md | 5 ----- .changeset/serious-ducks-care.md | 5 ----- .changeset/shiny-windows-remain.md | 7 ------- .changeset/sour-jobs-fold.md | 5 ----- packages/react/CHANGELOG.md | 21 +++++++++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 9 +++++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 10 ++++++++++ packages/system/package.json | 2 +- tooling/eslint-config/CHANGELOG.md | 7 +++++++ tooling/eslint-config/package.json | 2 +- 16 files changed, 51 insertions(+), 48 deletions(-) delete mode 100644 .changeset/brown-apples-deliver.md delete mode 100644 .changeset/cyan-pianos-lie.md delete mode 100644 .changeset/happy-hats-lay.md delete mode 100644 .changeset/polite-hounds-yawn.md delete mode 100644 .changeset/quick-cobras-report.md delete mode 100644 .changeset/serious-ducks-care.md delete mode 100644 .changeset/shiny-windows-remain.md delete mode 100644 .changeset/sour-jobs-fold.md create mode 100644 tooling/eslint-config/CHANGELOG.md diff --git a/.changeset/brown-apples-deliver.md b/.changeset/brown-apples-deliver.md deleted file mode 100644 index cf1754ad..00000000 --- a/.changeset/brown-apples-deliver.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/svelte': patch -'@xyflow/system': patch ---- - -Add more TSDocs to components, hooks, utils funcs and types diff --git a/.changeset/cyan-pianos-lie.md b/.changeset/cyan-pianos-lie.md deleted file mode 100644 index 2ff7301d..00000000 --- a/.changeset/cyan-pianos-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Fix viewport shifting on node focus diff --git a/.changeset/happy-hats-lay.md b/.changeset/happy-hats-lay.md deleted file mode 100644 index eb58de7d..00000000 --- a/.changeset/happy-hats-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Pass `NodeType` type argument from `ReactFlowProps` to `connectionLineComponent` property. diff --git a/.changeset/polite-hounds-yawn.md b/.changeset/polite-hounds-yawn.md deleted file mode 100644 index 790decaf..00000000 --- a/.changeset/polite-hounds-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Add package.json to exports diff --git a/.changeset/quick-cobras-report.md b/.changeset/quick-cobras-report.md deleted file mode 100644 index 68ed7250..00000000 --- a/.changeset/quick-cobras-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Add snapGrid option to screenToFlowPosition and set snapToGrid to false diff --git a/.changeset/serious-ducks-care.md b/.changeset/serious-ducks-care.md deleted file mode 100644 index 77c69a3d..00000000 --- a/.changeset/serious-ducks-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Make it possible to stop autoPanOnDrag by setting it to false diff --git a/.changeset/shiny-windows-remain.md b/.changeset/shiny-windows-remain.md deleted file mode 100644 index 6b8d6372..00000000 --- a/.changeset/shiny-windows-remain.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/system': patch -'@xyflow/eslint-config': patch ---- - -repair lint command diff --git a/.changeset/sour-jobs-fold.md b/.changeset/sour-jobs-fold.md deleted file mode 100644 index f21dc567..00000000 --- a/.changeset/sour-jobs-fold.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Prevent viewport shift after using Tab diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 3f3b6e31..43690aa3 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,26 @@ # @xyflow/react +## 12.4.3 + +### Patch Changes + +- [#5010](https://github.com/xyflow/xyflow/pull/5010) [`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919) Thanks [@moklick](https://github.com/moklick)! - Add more TSDocs to components, hooks, utils funcs and types + +- [#4991](https://github.com/xyflow/xyflow/pull/4991) [`ea54d9bc`](https://github.com/xyflow/xyflow/commit/ea54d9bcb197d02d248ef3e4eaabc033a43d966a) Thanks [@waynetee](https://github.com/waynetee)! - Fix viewport shifting on node focus + +- [#5013](https://github.com/xyflow/xyflow/pull/5013) [`cde899c5`](https://github.com/xyflow/xyflow/commit/cde899c5be9715c4ff2cc331ea93821102604c62) Thanks [@moklick](https://github.com/moklick)! - Pass `NodeType` type argument from `ReactFlowProps` to `connectionLineComponent` property. + +- [#5008](https://github.com/xyflow/xyflow/pull/5008) [`12d859fe`](https://github.com/xyflow/xyflow/commit/12d859fe297593d44cf8493a4d6bf2c664b9139c) Thanks [@moklick](https://github.com/moklick)! - Add package.json to exports + +- [#5012](https://github.com/xyflow/xyflow/pull/5012) [`4d3f19e8`](https://github.com/xyflow/xyflow/commit/4d3f19e88b984ce6743970560d7367d174500f32) Thanks [@moklick](https://github.com/moklick)! - Add snapGrid option to screenToFlowPosition and set snapToGrid to false + +- [#5003](https://github.com/xyflow/xyflow/pull/5003) [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - repair lint command + +- [#4991](https://github.com/xyflow/xyflow/pull/4991) [`4c62f19b`](https://github.com/xyflow/xyflow/commit/4c62f19b3afac4b3db84b14e2c36f8c9e0a96116) Thanks [@waynetee](https://github.com/waynetee)! - Prevent viewport shift after using Tab + +- Updated dependencies [[`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919), [`4947029c`](https://github.com/xyflow/xyflow/commit/4947029cd6cda0f695e1fb4815e4030adb232234), [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7)]: + - @xyflow/system@0.0.51 + ## 12.4.2 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 1cdf428c..6d4c3d1b 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.4.2", + "version": "12.4.3", "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 0a0e8306..3c7d743b 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,14 @@ # @xyflow/svelte +## 0.1.30 + +### Patch Changes + +- [#5010](https://github.com/xyflow/xyflow/pull/5010) [`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919) Thanks [@moklick](https://github.com/moklick)! - Add more TSDocs to components, hooks, utils funcs and types + +- Updated dependencies [[`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919), [`4947029c`](https://github.com/xyflow/xyflow/commit/4947029cd6cda0f695e1fb4815e4030adb232234), [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7)]: + - @xyflow/system@0.0.51 + ## 0.1.29 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index ab0542d7..aa8c1e9c 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.29", + "version": "0.1.30", "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 a1613ca3..5c6a5a91 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,15 @@ # @xyflow/system +## 0.0.51 + +### Patch Changes + +- [#5010](https://github.com/xyflow/xyflow/pull/5010) [`6c121d42`](https://github.com/xyflow/xyflow/commit/6c121d427fea9a11e86a85f95d2c12ba8af34919) Thanks [@moklick](https://github.com/moklick)! - Add more TSDocs to components, hooks, utils funcs and types + +- [#4990](https://github.com/xyflow/xyflow/pull/4990) [`4947029c`](https://github.com/xyflow/xyflow/commit/4947029cd6cda0f695e1fb4815e4030adb232234) Thanks [@damianstasik](https://github.com/damianstasik)! - Make it possible to stop autoPanOnDrag by setting it to false + +- [#5003](https://github.com/xyflow/xyflow/pull/5003) [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - repair lint command + ## 0.0.50 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index c7b1ee03..aa85a17c 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.50", + "version": "0.0.51", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", diff --git a/tooling/eslint-config/CHANGELOG.md b/tooling/eslint-config/CHANGELOG.md new file mode 100644 index 00000000..f10cdc0f --- /dev/null +++ b/tooling/eslint-config/CHANGELOG.md @@ -0,0 +1,7 @@ +# @xyflow/eslint-config + +## 0.0.1 + +### Patch Changes + +- [#5003](https://github.com/xyflow/xyflow/pull/5003) [`e8e0d684`](https://github.com/xyflow/xyflow/commit/e8e0d684957b95d53a6cc11598c8755ff02117c7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - repair lint command diff --git a/tooling/eslint-config/package.json b/tooling/eslint-config/package.json index d4aa78ee..48b1dcbb 100644 --- a/tooling/eslint-config/package.json +++ b/tooling/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/eslint-config", - "version": "0.0.0", + "version": "0.0.1", "private": true, "license": "MIT", "main": "src/index.js", From dbb34318133f27304b533f8a33a005146af6690c Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 16 Feb 2025 21:05:04 +0700 Subject: [PATCH 028/157] add `"./package.json": "./package.json",` in `exports` field in `package.json` --- packages/svelte/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/svelte/package.json b/packages/svelte/package.json index aa8c1e9c..ff62df7c 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -34,6 +34,7 @@ "type": "module", "module": "./dist/lib/index.js", "exports": { + "./package.json": "./package.json", ".": { "types": "./dist/lib/index.d.ts", "svelte": "./dist/lib/index.js", From 3e80317cf6da0e9fdc111c3ade88f2a88a10dbd6 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 16 Feb 2025 21:06:58 +0700 Subject: [PATCH 029/157] Create few-rice-drive.md --- .changeset/few-rice-drive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/few-rice-drive.md diff --git a/.changeset/few-rice-drive.md b/.changeset/few-rice-drive.md new file mode 100644 index 00000000..c72268c3 --- /dev/null +++ b/.changeset/few-rice-drive.md @@ -0,0 +1,5 @@ +--- +"@xyflow/svelte": patch +--- + +add `"./package.json": "./package.json",` in `exports` field in `package.json` From ae5f3666d4f2765fcdc3dbc04a5a2932fb43d045 Mon Sep 17 00:00:00 2001 From: Abbey Yacoe Date: Mon, 17 Feb 2025 10:42:11 +0100 Subject: [PATCH 030/157] docs(useNodeConnections): fix tsdocs typo --- packages/react/src/hooks/useNodeConnections.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/hooks/useNodeConnections.ts b/packages/react/src/hooks/useNodeConnections.ts index 60ba894c..6d6ad6b9 100644 --- a/packages/react/src/hooks/useNodeConnections.ts +++ b/packages/react/src/hooks/useNodeConnections.ts @@ -38,7 +38,7 @@ type UseNodeConnectionsParams = { * *export default function () { * const connections = useNodeConnections({ - * type: 'target', + * handleType: 'target', * handleId: 'my-handle', * }); * From 5867bba8050d07378a45a2026557c4bce7bda239 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Thu, 20 Feb 2025 16:03:44 +0700 Subject: [PATCH 031/157] lint: remove unnecessary type assertion --- .changeset/warm-pandas-retire.md | 5 +++++ .../react/src/components/BatchProvider/index.tsx | 4 ++-- packages/react/src/container/ZoomPane/index.tsx | 2 +- packages/react/src/hooks/useReactFlow.ts | 6 +++--- packages/react/src/hooks/useResizeHandler.ts | 2 +- packages/react/src/store/index.ts | 12 ++++++------ tooling/eslint-config/src/index.js | 11 +++++++++++ 7 files changed, 29 insertions(+), 13 deletions(-) create mode 100644 .changeset/warm-pandas-retire.md diff --git a/.changeset/warm-pandas-retire.md b/.changeset/warm-pandas-retire.md new file mode 100644 index 00000000..8da07c81 --- /dev/null +++ b/.changeset/warm-pandas-retire.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +lint: remove unnecessary type assertion diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 5a5d1ed3..0ef7e399 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -35,7 +35,7 @@ export function BatchProvider[]) => { const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState(); - let next = edges as EdgeType[]; + let next = edges; for (const payload of queueItems) { next = typeof payload === 'function' ? payload(next) : payload; } diff --git a/packages/react/src/container/ZoomPane/index.tsx b/packages/react/src/container/ZoomPane/index.tsx index 35fbb248..61af78e6 100644 --- a/packages/react/src/container/ZoomPane/index.tsx +++ b/packages/react/src/container/ZoomPane/index.tsx @@ -95,7 +95,7 @@ export function ZoomPane({ }, }); - const { x, y, zoom } = panZoom.current!.getViewport(); + const { x, y, zoom } = panZoom.current.getViewport(); store.setState({ panZoom: panZoom.current, diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index 57b2e001..8ffb15a6 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -95,7 +95,7 @@ export function useReactFlow prevNodes.map((node) => { if (node.id === id) { - const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node as NodeType) : nodeUpdate; + const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node) : nodeUpdate; return options.replace && isNode(nextNode) ? (nextNode as NodeType) : { ...node, ...nextNode }; } @@ -112,7 +112,7 @@ export function useReactFlow prevEdges.map((edge) => { if (edge.id === id) { - const nextEdge = typeof edgeUpdate === 'function' ? edgeUpdate(edge as EdgeType) : edgeUpdate; + const nextEdge = typeof edgeUpdate === 'function' ? edgeUpdate(edge) : edgeUpdate; return options.replace && isEdge(nextEdge) ? (nextEdge as EdgeType) : { ...edge, ...nextEdge }; } @@ -207,7 +207,7 @@ export function useReactFlow { const internalNode = store.getState().nodeLookup.get(n.id); - if (internalNode && !isRect && (n.id === nodeOrRect!.id || !internalNode.internals.positionAbsolute)) { + if (internalNode && !isRect && (n.id === nodeOrRect.id || !internalNode.internals.positionAbsolute)) { return false; } diff --git a/packages/react/src/hooks/useResizeHandler.ts b/packages/react/src/hooks/useResizeHandler.ts index 2db37499..4348208a 100644 --- a/packages/react/src/hooks/useResizeHandler.ts +++ b/packages/react/src/hooks/useResizeHandler.ts @@ -16,7 +16,7 @@ export function useResizeHandler(domNode: MutableRefObject createSelectionChange(nodeId, true)); - triggerNodeChanges(nodeChanges as NodeSelectionChange[]); + triggerNodeChanges(nodeChanges); return; } @@ -240,7 +240,7 @@ const createStore = ({ if (multiSelectionActive) { const changedEdges = selectedEdgeIds.map((edgeId) => createSelectionChange(edgeId, true)); - triggerEdgeChanges(changedEdges as EdgeSelectionChange[]); + triggerEdgeChanges(changedEdges); return; } @@ -265,8 +265,8 @@ const createStore = ({ }); const edgeChanges = edgesToUnselect.map((edge) => createSelectionChange(edge.id, false)); - triggerNodeChanges(nodeChanges as NodeSelectionChange[]); - triggerEdgeChanges(edgeChanges as EdgeSelectionChange[]); + triggerNodeChanges(nodeChanges); + triggerEdgeChanges(edgeChanges); }, setMinZoom: (minZoom) => { const { panZoom, maxZoom } = get(); @@ -292,11 +292,11 @@ const createStore = ({ const { edges, nodes, triggerNodeChanges, triggerEdgeChanges } = get(); const nodeChanges = nodes.reduce( - (res, node) => (node.selected ? [...res, createSelectionChange(node.id, false) as NodeSelectionChange] : res), + (res, node) => (node.selected ? [...res, createSelectionChange(node.id, false)] : res), [] ); const edgeChanges = edges.reduce( - (res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false) as EdgeSelectionChange] : res), + (res, edge) => (edge.selected ? [...res, createSelectionChange(edge.id, false)] : res), [] ); diff --git a/tooling/eslint-config/src/index.js b/tooling/eslint-config/src/index.js index f2ce34a0..0a80797e 100644 --- a/tooling/eslint-config/src/index.js +++ b/tooling/eslint-config/src/index.js @@ -29,4 +29,15 @@ module.exports = { rules: { '@typescript-eslint/no-non-null-assertion': 'off', }, + overrides: [ + { + files: ['**/*.{ts,tsx,cts,mts}'], + parserOptions: { + projectService: true, + }, + rules: { + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + }, + }, + ], }; From 7b4a81fb6b3d88f8ee7b4f070aef7ac3b962d5a6 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Thu, 20 Feb 2025 16:11:00 +0700 Subject: [PATCH 032/157] lint: use `React.JSX` type instead of the deprecated global `JSX` namespace --- .changeset/tame-llamas-approve.md | 5 +++++ packages/react/src/components/EdgeWrapper/index.tsx | 2 +- packages/react/src/utils/general.ts | 2 +- tooling/eslint-config/src/index.js | 11 +++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 .changeset/tame-llamas-approve.md diff --git a/.changeset/tame-llamas-approve.md b/.changeset/tame-llamas-approve.md new file mode 100644 index 00000000..61668347 --- /dev/null +++ b/.changeset/tame-llamas-approve.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +lint: use `React.JSX` type instead of the deprecated global `JSX` namespace diff --git a/packages/react/src/components/EdgeWrapper/index.tsx b/packages/react/src/components/EdgeWrapper/index.tsx index 2d3754fd..72c5c2f8 100644 --- a/packages/react/src/components/EdgeWrapper/index.tsx +++ b/packages/react/src/components/EdgeWrapper/index.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useRef, type KeyboardEvent, useCallback } from 'react'; +import { useState, useMemo, useRef, type KeyboardEvent, useCallback, JSX } from 'react'; import cc from 'classcat'; import { shallow } from 'zustand/shallow'; import { diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index f3cc26ea..52d8eee2 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -1,4 +1,4 @@ -import { type Ref, type RefAttributes, forwardRef } from 'react'; +import { type Ref, type RefAttributes, forwardRef, JSX } from 'react'; import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '../types'; diff --git a/tooling/eslint-config/src/index.js b/tooling/eslint-config/src/index.js index f2ce34a0..23d24b86 100644 --- a/tooling/eslint-config/src/index.js +++ b/tooling/eslint-config/src/index.js @@ -29,4 +29,15 @@ module.exports = { rules: { '@typescript-eslint/no-non-null-assertion': 'off', }, + overrides: [ + { + files: ['**/*.{ts,tsx,cts,mts}'], + parserOptions: { + projectService: true, + }, + rules: { + '@typescript-eslint/no-deprecated': 'error', + }, + }, + ], }; From 602627f5cc688c2e15c20196ea41987344cba714 Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Fri, 21 Feb 2025 16:31:59 +0100 Subject: [PATCH 033/157] Update few-rice-drive.md --- .changeset/few-rice-drive.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/few-rice-drive.md b/.changeset/few-rice-drive.md index c72268c3..ad46f2fe 100644 --- a/.changeset/few-rice-drive.md +++ b/.changeset/few-rice-drive.md @@ -2,4 +2,4 @@ "@xyflow/svelte": patch --- -add `"./package.json": "./package.json",` in `exports` field in `package.json` +Add `"./package.json" to the `exports` field so that users can import it From cb55ff26ef17e3c1692d6c93590abfc2cdd3ddae Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Fri, 21 Feb 2025 16:38:08 +0100 Subject: [PATCH 034/157] Update warm-pandas-retire.md --- .changeset/warm-pandas-retire.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/warm-pandas-retire.md b/.changeset/warm-pandas-retire.md index 8da07c81..ee52510c 100644 --- a/.changeset/warm-pandas-retire.md +++ b/.changeset/warm-pandas-retire.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -lint: remove unnecessary type assertion +lint: remove unnecessary type assertions From 43f188d3b1d1b3c639aa457aef8b0de0e16ac2cf Mon Sep 17 00:00:00 2001 From: moklick Date: Fri, 21 Feb 2025 17:52:08 +0100 Subject: [PATCH 035/157] fix(click-connections): handle isConnectableStart correctly #5041 --- .../react/src/components/Handle/index.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index df7b428b..b2c3373e 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -46,9 +46,7 @@ const selector = (s: ReactFlowState) => ({ const connectingSelector = (nodeId: string | null, handleId: string | null, type: HandleType) => (state: ReactFlowState) => { const { connectionClickStartHandle: clickHandle, connectionMode, connection } = state; - const { fromHandle, toHandle, isValid } = connection; - const connectingTo = toHandle?.nodeId === nodeId && toHandle?.id === handleId && toHandle?.type === type; return { @@ -60,6 +58,7 @@ const connectingSelector = ? fromHandle?.type !== type : nodeId !== fromHandle?.nodeId || handleId !== fromHandle?.id, connectionInProcess: !!fromHandle, + clickConnectionInProcess: !!clickHandle, valid: connectingTo && isValid, }; }; @@ -87,11 +86,15 @@ function HandleComponent( const store = useStoreApi(); const nodeId = useNodeId(); const { connectOnClick, noPanClassName, rfId } = useStore(selector, shallow); - const { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore( - connectingSelector(nodeId, handleId, type), - shallow - ); - + const { + connectingFrom, + connectingTo, + clickConnecting, + isPossibleEndHandle, + connectionInProcess, + clickConnectionInProcess, + valid, + } = useStore(connectingSelector(nodeId, handleId, type), shallow); if (!nodeId) { store.getState().onError?.('010', errorMessages['error010']()); } @@ -239,7 +242,7 @@ function HandleComponent( connectionindicator: isConnectable && (!connectionInProcess || isPossibleEndHandle) && - (connectionInProcess ? isConnectableEnd : isConnectableStart), + (connectionInProcess || clickConnectionInProcess ? isConnectableEnd : isConnectableStart), }, ])} onMouseDown={onPointerDown} From 2fe0e850a8c415c6a3113796a2c5c80e7cad2376 Mon Sep 17 00:00:00 2001 From: moklick Date: Fri, 21 Feb 2025 17:54:33 +0100 Subject: [PATCH 036/157] chore(changeset): add --- .changeset/late-pugs-thank.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/late-pugs-thank.md diff --git a/.changeset/late-pugs-thank.md b/.changeset/late-pugs-thank.md new file mode 100644 index 00000000..56413165 --- /dev/null +++ b/.changeset/late-pugs-thank.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Allow click connections when target sets `isConnectableStart` From 3969758af25702a56c9d14366aa35b208f1f82bd Mon Sep 17 00:00:00 2001 From: moklick Date: Fri, 21 Feb 2025 18:22:05 +0100 Subject: [PATCH 037/157] refactor(expandParent): use current value on drag #5039 --- packages/react/src/store/index.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 2d0552c0..e3b5279a 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -51,7 +51,7 @@ const createStore = ({ * setNodes() is called exclusively in response to user actions: * - either when the `` prop is updated in the controlled ReactFlow setup, * - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup. - * + * * When this happens, we take the note objects passed by the user and extend them with fields * relevant for internal React Flow operations. */ @@ -154,16 +154,18 @@ const createStore = ({ const changes = []; for (const [id, dragItem] of nodeDragItems) { - const expandParent = !!(dragItem?.expandParent && dragItem?.parentId && dragItem?.position); + // we are using the nodelookup to be sure to use the current expandParent and parentId value + const node = get().nodeLookup.get(id); + const expandParent = !!(node?.expandParent && node?.parentId && dragItem?.position); const change: NodeChange = { id, type: 'position', position: expandParent ? { - x: Math.max(0, dragItem.position.x), - y: Math.max(0, dragItem.position.y), - } + x: Math.max(0, dragItem.position.x), + y: Math.max(0, dragItem.position.y), + } : dragItem.position, dragging, }; @@ -171,7 +173,7 @@ const createStore = ({ if (expandParent) { parentExpandChildren.push({ id, - parentId: dragItem.parentId!, + parentId: node.parentId!, rect: { ...dragItem.internals.positionAbsolute, width: dragItem.measured.width!, From 0292ad20109a3b2518dc686a82e100a0a6964fb8 Mon Sep 17 00:00:00 2001 From: moklick Date: Fri, 21 Feb 2025 18:22:54 +0100 Subject: [PATCH 038/157] chore(changeset): add --- .changeset/ten-waves-remain.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/ten-waves-remain.md diff --git a/.changeset/ten-waves-remain.md b/.changeset/ten-waves-remain.md new file mode 100644 index 00000000..9210e772 --- /dev/null +++ b/.changeset/ten-waves-remain.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Use current expandParent value on drag to be able to update it while dragging From d094ef0581fa743410c211d1ea73941ac83e02d0 Mon Sep 17 00:00:00 2001 From: moklick Date: Sun, 23 Feb 2025 18:32:43 +0100 Subject: [PATCH 039/157] fix(OnSelectionChangeFunc): pass node and edge type generics #5023 --- packages/react/src/hooks/useOnSelectionChange.ts | 12 +++++++----- packages/react/src/types/component-props.ts | 4 ++-- packages/react/src/types/general.ts | 16 +++++++++------- packages/react/src/types/store.ts | 4 ++-- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/react/src/hooks/useOnSelectionChange.ts b/packages/react/src/hooks/useOnSelectionChange.ts index 65cad6fd..17232895 100644 --- a/packages/react/src/hooks/useOnSelectionChange.ts +++ b/packages/react/src/hooks/useOnSelectionChange.ts @@ -1,10 +1,10 @@ import { useEffect } from 'react'; import { useStoreApi } from './useStore'; -import type { OnSelectionChangeFunc } from '../types'; +import type { OnSelectionChangeFunc, Node, Edge } from '../types'; -export type UseOnSelectionChangeOptions = { - onChange: OnSelectionChangeFunc; +export type UseOnSelectionChangeOptions = { + onChange: OnSelectionChangeFunc; }; /** @@ -45,8 +45,10 @@ export type UseOnSelectionChangeOptions = { * * @remarks You need to memoize the passed `onChange` handler, otherwise the hook will not work correctly. */ -export function useOnSelectionChange({ onChange }: UseOnSelectionChangeOptions) { - const store = useStoreApi(); +export function useOnSelectionChange({ + onChange, +}: UseOnSelectionChangeOptions) { + const store = useStoreApi(); useEffect(() => { const nextOnSelectionChangeHandlers = [...store.getState().onSelectionChangeHandlers, onChange]; diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index b7c414f1..d558bc47 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -216,7 +216,7 @@ export interface ReactFlowProps; /** This event handler gets called when user scroll inside the pane */ onPaneScroll?: (event?: WheelEvent) => void; /** This event handler gets called when user clicks inside the pane */ @@ -316,7 +316,7 @@ export interface ReactFlowProps >; -export type UnselectNodesAndEdgesParams = { - nodes?: Node[]; - edges?: Edge[]; +export type UnselectNodesAndEdgesParams = { + nodes?: NodeType[]; + edges?: EdgeType[]; }; -export type OnSelectionChangeParams = { - nodes: Node[]; - edges: Edge[]; +export type OnSelectionChangeParams = { + nodes: NodeType[]; + edges: EdgeType[]; }; -export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void; +export type OnSelectionChangeFunc = ( + params: OnSelectionChangeParams +) => void; export type FitViewParams = FitViewParamsBase; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index b060be36..e0ec76fa 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -134,7 +134,7 @@ export type ReactFlowStore; - onSelectionChangeHandlers: OnSelectionChangeFunc[]; + onSelectionChangeHandlers: OnSelectionChangeFunc[]; ariaLiveMessage: string; autoPanOnConnect: boolean; @@ -155,7 +155,7 @@ export type ReactFlowActions = { updateNodeInternals: (updates: Map, params?: { triggerFitView: boolean }) => void; updateNodePositions: UpdateNodePositions; resetSelectedElements: () => void; - unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void; + unselectNodesAndEdges: (params?: UnselectNodesAndEdgesParams) => void; addSelectedNodes: (nodeIds: string[]) => void; addSelectedEdges: (edgeIds: string[]) => void; setMinZoom: (minZoom: number) => void; From b3bf5693c659069cea90bf1cb215ae65d06c5509 Mon Sep 17 00:00:00 2001 From: moklick Date: Sun, 23 Feb 2025 18:33:28 +0100 Subject: [PATCH 040/157] chore(changeset): add --- .changeset/old-moles-push.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/old-moles-push.md diff --git a/.changeset/old-moles-push.md b/.changeset/old-moles-push.md new file mode 100644 index 00000000..ea79bbba --- /dev/null +++ b/.changeset/old-moles-push.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Pass generics to OnSelectionChangeFunc so that users can type it correctly From 27df80b6a60c05678b22eae48160f0e137b6eedc Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 24 Feb 2025 08:58:24 +0100 Subject: [PATCH 041/157] fix(selection-listener): pass generics --- .../src/components/SelectionListener/index.tsx | 18 +++++++++++------- .../react/src/container/ReactFlow/index.tsx | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/react/src/components/SelectionListener/index.tsx b/packages/react/src/components/SelectionListener/index.tsx index 6a9a03a6..89ed2c26 100644 --- a/packages/react/src/components/SelectionListener/index.tsx +++ b/packages/react/src/components/SelectionListener/index.tsx @@ -10,8 +10,8 @@ import { shallow } from 'zustand/shallow'; import { useStore, useStoreApi } from '../../hooks/useStore'; import type { ReactFlowState, OnSelectionChangeFunc, Node, Edge } from '../../types'; -type SelectionListenerProps = { - onSelectionChange?: OnSelectionChangeFunc; +type SelectionListenerProps = { + onSelectionChange?: OnSelectionChangeFunc; }; const selector = (s: ReactFlowState) => { @@ -44,12 +44,14 @@ function areEqual(a: SelectorSlice, b: SelectorSlice) { ); } -function SelectionListenerInner({ onSelectionChange }: SelectionListenerProps) { - const store = useStoreApi(); +function SelectionListenerInner({ + onSelectionChange, +}: SelectionListenerProps) { + const store = useStoreApi(); const { selectedNodes, selectedEdges } = useStore(selector, areEqual); useEffect(() => { - const params = { nodes: selectedNodes, edges: selectedEdges }; + const params = { nodes: selectedNodes as NodeType[], edges: selectedEdges as EdgeType[] }; onSelectionChange?.(params); store.getState().onSelectionChangeHandlers.forEach((fn) => fn(params)); @@ -60,11 +62,13 @@ function SelectionListenerInner({ onSelectionChange }: SelectionListenerProps) { const changeSelector = (s: ReactFlowState) => !!s.onSelectionChangeHandlers; -export function SelectionListener({ onSelectionChange }: SelectionListenerProps) { +export function SelectionListener({ + onSelectionChange, +}: SelectionListenerProps) { const storeHasSelectionChangeHandlers = useStore(changeSelector); if (onSelectionChange || storeHasSelectionChangeHandlers) { - return ; + return onSelectionChange={onSelectionChange} />; } return null; diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index cfc4f40c..31389887 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -303,7 +303,7 @@ function ReactFlow( paneClickDistance={paneClickDistance} debug={debug} /> - + onSelectionChange={onSelectionChange} /> {children} From 0b67a6c303d31c814fdce53a7772b6b0a80022bd Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 25 Feb 2025 10:52:54 +0100 Subject: [PATCH 042/157] refactor(errors): show error when user drags uninitialized node #5014 --- examples/react/src/App/routes.ts | 6 ++ .../react/src/examples/BrokenNodes/index.tsx | 80 +++++++++++++++++++ .../NodeResizer/NodeResizeControl.tsx | 4 +- packages/react/src/store/index.ts | 12 +-- packages/system/src/constants.ts | 2 + packages/system/src/utils/graph.ts | 8 +- 6 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 examples/react/src/examples/BrokenNodes/index.tsx diff --git a/examples/react/src/App/routes.ts b/examples/react/src/App/routes.ts index cb184b4a..2256ce52 100644 --- a/examples/react/src/App/routes.ts +++ b/examples/react/src/App/routes.ts @@ -1,5 +1,6 @@ import Basic from '../examples/Basic'; import Backgrounds from '../examples/Backgrounds'; +import BrokenNodes from '../examples/BrokenNodes'; import ColorMode from '../examples/ColorMode'; import ClickDistance from '../examples/ClickDistance'; import ControlledUncontrolled from '../examples/ControlledUncontrolled'; @@ -77,6 +78,11 @@ const routes: IRoute[] = [ path: 'backgrounds', component: Backgrounds, }, + { + name: 'Broken Nodes', + path: 'broken-nodes', + component: BrokenNodes, + }, { name: 'Color Mode', path: 'color-mode', diff --git a/examples/react/src/examples/BrokenNodes/index.tsx b/examples/react/src/examples/BrokenNodes/index.tsx new file mode 100644 index 00000000..990612f9 --- /dev/null +++ b/examples/react/src/examples/BrokenNodes/index.tsx @@ -0,0 +1,80 @@ +import { useCallback, useState } from 'react'; +import { ReactFlow, addEdge, Node, Connection, Edge, OnNodeDrag } from '@xyflow/react'; + +const nodesInit: Node[] = [ + { + id: '1a', + type: 'input', + data: { label: 'Node 1' }, + position: { x: 250, y: 5 }, + className: 'light', + ariaLabel: 'Input Node 1', + }, + { + id: '2a', + data: { label: 'Node 2' }, + position: { x: 100, y: 100 }, + className: 'light', + ariaLabel: 'Default Node 2', + }, + { + id: '3a', + data: { label: 'Node 3' }, + position: { x: 400, y: 100 }, + className: 'light', + }, + { + id: '4a', + data: { label: 'Node 4' }, + position: { x: 400, y: 200 }, + className: 'light', + }, +]; + +const edgesInit: Edge[] = [ + { id: 'e1-2', source: '1a', target: '2a', ariaLabel: undefined }, + { id: 'e1-3', source: '1a', target: '3a' }, +]; + +const onNodesChange = () => {}; +const onEdgesChange = () => {}; +const BasicFlow = () => { + const [nodes, setNodes] = useState(nodesInit); + const [edges, setEdges] = useState(edgesInit); + + const onConnect = useCallback((params: Connection | Edge) => setEdges((eds) => addEdge(params, eds)), [setEdges]); + + const onNodeDrag: OnNodeDrag = useCallback((e, node) => { + if (isNaN(node.position.x) || isNaN(node.position.y)) { + console.log('received NaN', node.position); + } + + setNodes((nds) => { + return nds.map((item) => { + if (item.id === node.id) { + return { + ...item, + position: { + x: node.position.x, + y: node.position.y, + }, + }; + } + return item; + }); + }); + }, []); + + return ( + + ); +}; + +export default BasicFlow; diff --git a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx index 8a2faea7..5be4eafd 100644 --- a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx +++ b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx @@ -74,8 +74,8 @@ function ResizeControl({ if (node && node.expandParent && node.parentId) { const origin = node.origin ?? nodeOrigin; - const width = change.width ?? node.measured.width!; - const height = change.height ?? node.measured.height!; + const width = change.width ?? node.measured.width ?? 0; + const height = change.height ?? node.measured.height ?? 0; const child: ParentExpandChild = { id: node.id, diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 2d0552c0..5711102b 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -51,7 +51,7 @@ const createStore = ({ * setNodes() is called exclusively in response to user actions: * - either when the `` prop is updated in the controlled ReactFlow setup, * - or when the user calls something like `reactFlowInstance.setNodes()` in an uncontrolled ReactFlow setup. - * + * * When this happens, we take the note objects passed by the user and extend them with fields * relevant for internal React Flow operations. */ @@ -161,9 +161,9 @@ const createStore = ({ type: 'position', position: expandParent ? { - x: Math.max(0, dragItem.position.x), - y: Math.max(0, dragItem.position.y), - } + x: Math.max(0, dragItem.position.x), + y: Math.max(0, dragItem.position.y), + } : dragItem.position, dragging, }; @@ -174,8 +174,8 @@ const createStore = ({ parentId: dragItem.parentId!, rect: { ...dragItem.internals.positionAbsolute, - width: dragItem.measured.width!, - height: dragItem.measured.height!, + width: dragItem.measured.width ?? 0, + height: dragItem.measured.height ?? 0, }, }); } diff --git a/packages/system/src/constants.ts b/packages/system/src/constants.ts index 921189fa..9bb65656 100644 --- a/packages/system/src/constants.ts +++ b/packages/system/src/constants.ts @@ -26,6 +26,8 @@ export const errorMessages = { `It seems that you haven't loaded the styles. Please import '@xyflow/${lib}/dist/style.css' or base.css to make sure everything is working properly.`, error014: () => 'useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.', + error015: () => + 'It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs.', }; export const infiniteExtent: CoordinateExtent = [ diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index b2b1e6e5..9720e8c5 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -428,10 +428,14 @@ export function calculateNodePosition({ ? clampPosition(nextPosition, extent, node.measured) : nextPosition; + if (node.measured.width === undefined || node.measured.height === undefined) { + onError?.('015', errorMessages['error015']()); + } + return { position: { - x: positionAbsolute.x - parentX + node.measured.width! * origin[0], - y: positionAbsolute.y - parentY + node.measured.height! * origin[1], + x: positionAbsolute.x - parentX + (node.measured.width ?? 0) * origin[0], + y: positionAbsolute.y - parentY + (node.measured.height ?? 0) * origin[1], }, positionAbsolute, }; From 99dd7d3549e7423e7d103b2c956c8b37f5747b90 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 25 Feb 2025 10:53:51 +0100 Subject: [PATCH 043/157] chore(changeset): add --- .changeset/calm-pumpkins-relate.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/calm-pumpkins-relate.md diff --git a/.changeset/calm-pumpkins-relate.md b/.changeset/calm-pumpkins-relate.md new file mode 100644 index 00000000..f3c59706 --- /dev/null +++ b/.changeset/calm-pumpkins-relate.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/system': patch +--- + +Show an error if user drags uninitialized node From 8dd2b4f9e2ece77f5ffc075aab68ebd7774f722b Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 25 Feb 2025 10:57:17 +0100 Subject: [PATCH 044/157] chore(updateNodePositions): cleanup --- packages/react/src/store/index.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index e3b5279a..19a885a2 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -152,10 +152,11 @@ const createStore = ({ updateNodePositions: (nodeDragItems, dragging = false) => { const parentExpandChildren: ParentExpandChild[] = []; const changes = []; + const { nodeLookup, triggerNodeChanges } = get(); for (const [id, dragItem] of nodeDragItems) { // we are using the nodelookup to be sure to use the current expandParent and parentId value - const node = get().nodeLookup.get(id); + const node = nodeLookup.get(id); const expandParent = !!(node?.expandParent && node?.parentId && dragItem?.position); const change: NodeChange = { @@ -170,10 +171,10 @@ const createStore = ({ dragging, }; - if (expandParent) { + if (expandParent && node.parentId) { parentExpandChildren.push({ id, - parentId: node.parentId!, + parentId: node.parentId, rect: { ...dragItem.internals.positionAbsolute, width: dragItem.measured.width!, @@ -186,12 +187,12 @@ const createStore = ({ } if (parentExpandChildren.length > 0) { - const { nodeLookup, parentLookup, nodeOrigin } = get(); + const { parentLookup, nodeOrigin } = get(); const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin); changes.push(...parentExpandChanges); } - get().triggerNodeChanges(changes); + triggerNodeChanges(changes); }, triggerNodeChanges: (changes) => { const { onNodesChange, setNodes, nodes, hasDefaultNodes, debug } = get(); From 7a00fe3520428f0e98803017e3082786453f0b4d Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 25 Feb 2025 11:03:14 +0100 Subject: [PATCH 045/157] chore(getNodeConnections): remove deprecation #5051 --- packages/react/src/types/instance.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts index 85d66651..fce67ec5 100644 --- a/packages/react/src/types/instance.ts +++ b/packages/react/src/types/instance.ts @@ -203,7 +203,6 @@ export type GeneralHelpers HandleConnection[]; /** * Gets all connections to a node. Can be filtered by handle type and id. - * @deprecated use `getNodeConnections` instead * @param type - handle type 'source' or 'target' * @param handleId - 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 @@ -219,7 +218,6 @@ export type GeneralHelpers NodeConnection[]; }; - /** * The `ReactFlowInstance` provides a collection of methods to query and manipulate * the internal state of your flow. You can get an instance by using the From 25fb45b5e9d6da391b9aff652b8e6e34eaf757fc Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 25 Feb 2025 11:04:16 +0100 Subject: [PATCH 046/157] chore(changeset): add --- .changeset/red-geese-cry.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/red-geese-cry.md diff --git a/.changeset/red-geese-cry.md b/.changeset/red-geese-cry.md new file mode 100644 index 00000000..f959708f --- /dev/null +++ b/.changeset/red-geese-cry.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Remove incorrect deprecation warning From d045503667a096c9f7410fd60e48624d2807a24b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Feb 2025 10:21:58 +0000 Subject: [PATCH 047/157] chore(packages): bump --- .changeset/calm-pumpkins-relate.md | 6 ------ .changeset/few-rice-drive.md | 5 ----- .changeset/late-pugs-thank.md | 5 ----- .changeset/old-moles-push.md | 5 ----- .changeset/red-geese-cry.md | 5 ----- .changeset/tame-llamas-approve.md | 5 ----- .changeset/ten-waves-remain.md | 5 ----- .changeset/warm-pandas-retire.md | 5 ----- packages/react/CHANGELOG.md | 21 +++++++++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 9 +++++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 6 ++++++ packages/system/package.json | 2 +- 14 files changed, 39 insertions(+), 44 deletions(-) delete mode 100644 .changeset/calm-pumpkins-relate.md delete mode 100644 .changeset/few-rice-drive.md delete mode 100644 .changeset/late-pugs-thank.md delete mode 100644 .changeset/old-moles-push.md delete mode 100644 .changeset/red-geese-cry.md delete mode 100644 .changeset/tame-llamas-approve.md delete mode 100644 .changeset/ten-waves-remain.md delete mode 100644 .changeset/warm-pandas-retire.md diff --git a/.changeset/calm-pumpkins-relate.md b/.changeset/calm-pumpkins-relate.md deleted file mode 100644 index f3c59706..00000000 --- a/.changeset/calm-pumpkins-relate.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/system': patch ---- - -Show an error if user drags uninitialized node diff --git a/.changeset/few-rice-drive.md b/.changeset/few-rice-drive.md deleted file mode 100644 index ad46f2fe..00000000 --- a/.changeset/few-rice-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@xyflow/svelte": patch ---- - -Add `"./package.json" to the `exports` field so that users can import it diff --git a/.changeset/late-pugs-thank.md b/.changeset/late-pugs-thank.md deleted file mode 100644 index 56413165..00000000 --- a/.changeset/late-pugs-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Allow click connections when target sets `isConnectableStart` diff --git a/.changeset/old-moles-push.md b/.changeset/old-moles-push.md deleted file mode 100644 index ea79bbba..00000000 --- a/.changeset/old-moles-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Pass generics to OnSelectionChangeFunc so that users can type it correctly diff --git a/.changeset/red-geese-cry.md b/.changeset/red-geese-cry.md deleted file mode 100644 index f959708f..00000000 --- a/.changeset/red-geese-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Remove incorrect deprecation warning diff --git a/.changeset/tame-llamas-approve.md b/.changeset/tame-llamas-approve.md deleted file mode 100644 index 61668347..00000000 --- a/.changeset/tame-llamas-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -lint: use `React.JSX` type instead of the deprecated global `JSX` namespace diff --git a/.changeset/ten-waves-remain.md b/.changeset/ten-waves-remain.md deleted file mode 100644 index 9210e772..00000000 --- a/.changeset/ten-waves-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Use current expandParent value on drag to be able to update it while dragging diff --git a/.changeset/warm-pandas-retire.md b/.changeset/warm-pandas-retire.md deleted file mode 100644 index ee52510c..00000000 --- a/.changeset/warm-pandas-retire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -lint: remove unnecessary type assertions diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 43690aa3..baa007ba 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,26 @@ # @xyflow/react +## 12.4.4 + +### Patch Changes + +- [#5052](https://github.com/xyflow/xyflow/pull/5052) [`99dd7d35`](https://github.com/xyflow/xyflow/commit/99dd7d3549e7423e7d103b2c956c8b37f5747b90) Thanks [@moklick](https://github.com/moklick)! - Show an error if user drags uninitialized node + +- [#5042](https://github.com/xyflow/xyflow/pull/5042) [`2fe0e850`](https://github.com/xyflow/xyflow/commit/2fe0e850a8c415c6a3113796a2c5c80e7cad2376) Thanks [@moklick](https://github.com/moklick)! - Allow click connections when target sets `isConnectableStart` + +- [#5047](https://github.com/xyflow/xyflow/pull/5047) [`b3bf5693`](https://github.com/xyflow/xyflow/commit/b3bf5693c659069cea90bf1cb215ae65d06c5509) Thanks [@moklick](https://github.com/moklick)! - Pass generics to OnSelectionChangeFunc so that users can type it correctly + +- [#5053](https://github.com/xyflow/xyflow/pull/5053) [`25fb45b5`](https://github.com/xyflow/xyflow/commit/25fb45b5e9d6da391b9aff652b8e6e34eaf757fc) Thanks [@moklick](https://github.com/moklick)! - Remove incorrect deprecation warning + +- [#5033](https://github.com/xyflow/xyflow/pull/5033) [`7b4a81fb`](https://github.com/xyflow/xyflow/commit/7b4a81fb6b3d88f8ee7b4f070aef7ac3b962d5a6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - lint: use `React.JSX` type instead of the deprecated global `JSX` namespace + +- [#5043](https://github.com/xyflow/xyflow/pull/5043) [`0292ad20`](https://github.com/xyflow/xyflow/commit/0292ad20109a3b2518dc686a82e100a0a6964fb8) Thanks [@moklick](https://github.com/moklick)! - Use current expandParent value on drag to be able to update it while dragging + +- [#5032](https://github.com/xyflow/xyflow/pull/5032) [`5867bba8`](https://github.com/xyflow/xyflow/commit/5867bba8050d07378a45a2026557c4bce7bda239) Thanks [@dimaMachina](https://github.com/dimaMachina)! - lint: remove unnecessary type assertions + +- Updated dependencies [[`99dd7d35`](https://github.com/xyflow/xyflow/commit/99dd7d3549e7423e7d103b2c956c8b37f5747b90)]: + - @xyflow/system@0.0.52 + ## 12.4.3 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 6d4c3d1b..c69a7856 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.4.3", + "version": "12.4.4", "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 3c7d743b..12446c10 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,14 @@ # @xyflow/svelte +## 0.1.31 + +### Patch Changes + +- [#5019](https://github.com/xyflow/xyflow/pull/5019) [`3e80317c`](https://github.com/xyflow/xyflow/commit/3e80317cf6da0e9fdc111c3ade88f2a88a10dbd6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Add `"./package.json" to the `exports` field so that users can import it + +- Updated dependencies [[`99dd7d35`](https://github.com/xyflow/xyflow/commit/99dd7d3549e7423e7d103b2c956c8b37f5747b90)]: + - @xyflow/system@0.0.52 + ## 0.1.30 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index ff62df7c..18533e9f 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.30", + "version": "0.1.31", "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 5c6a5a91..d4fc2de0 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,11 @@ # @xyflow/system +## 0.0.52 + +### Patch Changes + +- [#5052](https://github.com/xyflow/xyflow/pull/5052) [`99dd7d35`](https://github.com/xyflow/xyflow/commit/99dd7d3549e7423e7d103b2c956c8b37f5747b90) Thanks [@moklick](https://github.com/moklick)! - Show an error if user drags uninitialized node + ## 0.0.51 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index aa85a17c..9f45b7ef 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.51", + "version": "0.0.52", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From dfc28c7a15a6eb5de754e5c1c02f016738ea1a1d Mon Sep 17 00:00:00 2001 From: Daniel Darabos Date: Tue, 25 Feb 2025 19:57:59 +0100 Subject: [PATCH 048/157] Always allow releasing keys. --- packages/react/src/hooks/useKeyPress.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index 00cd012b..b2928baa 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -106,13 +106,6 @@ export function useKeyPress( }; const upHandler = (event: KeyboardEvent) => { - const preventAction = - (!modifierPressed.current || (modifierPressed.current && !options.actInsideInputWithModifier)) && - isInputDOMNode(event); - - if (preventAction) { - return false; - } const keyOrCode = useKeyOrCode(event.code, keysToWatch); if (isMatchingKey(keyCodes, pressedKeys.current, true)) { From 4891e9cc1c63d67853cf717dc60e1d947666ed39 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 28 Feb 2025 07:38:44 +0100 Subject: [PATCH 049/157] fix(react,svelte): prevent pane click when connection is in progress --- packages/react/src/container/Pane/index.tsx | 6 ++++-- packages/svelte/src/lib/container/Pane/Pane.svelte | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/react/src/container/Pane/index.tsx b/packages/react/src/container/Pane/index.tsx index 91459539..4d2e392a 100644 --- a/packages/react/src/container/Pane/index.tsx +++ b/packages/react/src/container/Pane/index.tsx @@ -61,6 +61,7 @@ const wrapHandler = ( const selector = (s: ReactFlowState) => ({ userSelectionActive: s.userSelectionActive, elementsSelectable: s.elementsSelectable, + connectionInProgress: s.connection.inProgress, dragging: s.paneDragging, }); @@ -81,7 +82,7 @@ export function Pane({ children, }: PaneProps) { const store = useStoreApi(); - const { userSelectionActive, elementsSelectable, dragging } = useStore(selector, shallow); + const { userSelectionActive, elementsSelectable, dragging, connectionInProgress } = useStore(selector, shallow); const hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive); const container = useRef(null); @@ -96,7 +97,8 @@ export function Pane({ const onClick = (event: ReactMouseEvent) => { // We prevent click events when the user let go of the selectionKey during a selection - if (selectionInProgress.current) { + // We also prevent click events when a connection is in progress + if (selectionInProgress.current || connectionInProgress) { selectionInProgress.current = false; return; } diff --git a/packages/svelte/src/lib/container/Pane/Pane.svelte b/packages/svelte/src/lib/container/Pane/Pane.svelte index aaa36560..c2200935 100644 --- a/packages/svelte/src/lib/container/Pane/Pane.svelte +++ b/packages/svelte/src/lib/container/Pane/Pane.svelte @@ -63,7 +63,8 @@ selectionKeyPressed, selectionMode, panActivationKeyPressed, - unselectNodesAndEdges + unselectNodesAndEdges, + connection, } = useStore(); let container: HTMLDivElement; @@ -80,7 +81,8 @@ function onClick(event: MouseEvent | TouchEvent) { // We prevent click events when the user let go of the selectionKey during a selection - if (selectionInProgress) { + // We also prevent click events when a connection is in progress + if (selectionInProgress || $connection.inProgress) { selectionInProgress = false; return; } From 065ff89d10488f9c76c56870511e45eaed299778 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 28 Feb 2025 07:51:58 +0100 Subject: [PATCH 050/157] chore(changeset): add --- .changeset/famous-impalas-relate.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/famous-impalas-relate.md diff --git a/.changeset/famous-impalas-relate.md b/.changeset/famous-impalas-relate.md new file mode 100644 index 00000000..318bcc30 --- /dev/null +++ b/.changeset/famous-impalas-relate.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/svelte': patch +--- + +Prevent onPaneClick when connection is in progress. Closes [#5057](https://github.com/xyflow/xyflow/issues/5057) From ee1ef205ebdc01d357465afacbda5988400f4daf Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 13:45:28 +0100 Subject: [PATCH 051/157] Refactor fitView --- examples/react/src/examples/Basic/index.tsx | 16 ++- .../src/components/StoreUpdater/index.tsx | 4 +- packages/react/src/hooks/useReactFlow.ts | 14 +- packages/react/src/hooks/useViewportHelper.ts | 25 ---- packages/react/src/store/index.ts | 121 +++++------------- packages/react/src/store/initialState.ts | 6 +- packages/react/src/types/general.ts | 13 +- packages/react/src/types/instance.ts | 13 +- packages/react/src/types/store.ts | 7 +- packages/system/src/utils/graph.ts | 22 ++-- packages/system/src/utils/store.ts | 9 +- 11 files changed, 99 insertions(+), 151 deletions(-) diff --git a/examples/react/src/examples/Basic/index.tsx b/examples/react/src/examples/Basic/index.tsx index 62232a35..bb53b309 100644 --- a/examples/react/src/examples/Basic/index.tsx +++ b/examples/react/src/examples/Basic/index.tsx @@ -56,8 +56,18 @@ const initialEdges: Edge[] = [ const defaultEdgeOptions = {}; const BasicFlow = () => { - const { addNodes, setNodes, getNodes, setEdges, getEdges, deleteElements, updateNodeData, toObject, setViewport } = - useReactFlow(); + const { + addNodes, + setNodes, + getNodes, + setEdges, + getEdges, + deleteElements, + updateNodeData, + toObject, + setViewport, + fitView, + } = useReactFlow(); const updatePos = () => { setNodes((nodes) => @@ -104,6 +114,7 @@ const BasicFlow = () => { ]); setEdges([{ id: 'a-b', source: 'a', target: 'b' }]); + fitView(); }; const onUpdateNode = () => { @@ -117,6 +128,7 @@ const BasicFlow = () => { position: { x: Math.random() * 300, y: Math.random() * 300 }, className: 'light', }); + fitView(); }; return ( diff --git a/packages/react/src/components/StoreUpdater/index.tsx b/packages/react/src/components/StoreUpdater/index.tsx index e3a61ab2..ac9122ba 100644 --- a/packages/react/src/components/StoreUpdater/index.tsx +++ b/packages/react/src/components/StoreUpdater/index.tsx @@ -154,8 +154,8 @@ export function StoreUpdater !!s.panZoom; @@ -271,6 +279,10 @@ export function useReactFlow | undefined) => { + store.setState({ fitViewQueued: true, fitViewOptions: options }); + batchContext.nodeQueue.push((nodes) => [...nodes]); + }, }; }, []); diff --git a/packages/react/src/hooks/useViewportHelper.ts b/packages/react/src/hooks/useViewportHelper.ts index 9a773d14..a88bd3fc 100644 --- a/packages/react/src/hooks/useViewportHelper.ts +++ b/packages/react/src/hooks/useViewportHelper.ts @@ -2,11 +2,8 @@ import { useMemo } from 'react'; import { pointToRendererPoint, getViewportForBounds, - getFitViewNodes, - fitView, type XYPosition, rendererPointToPoint, - getDimensions, SnapGrid, } from '@xyflow/system'; @@ -65,28 +62,6 @@ const useViewportHelper = (): ViewportHelperFunctions => { const [x, y, zoom] = store.getState().transform; return { x, y, zoom }; }, - fitView: (options) => { - const { nodeLookup, minZoom, maxZoom, panZoom, domNode } = store.getState(); - - if (!panZoom || !domNode) { - return Promise.resolve(false); - } - - const fitViewNodes = getFitViewNodes(nodeLookup, options); - const { width, height } = getDimensions(domNode); - - return fitView( - { - nodes: fitViewNodes, - width, - height, - minZoom, - maxZoom, - panZoom, - }, - options - ); - }, setCenter: async (x, y, options) => { const { width, height, maxZoom, panZoom } = store.getState(); const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom; diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index bb05ae22..64d1b405 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -1,7 +1,5 @@ import { createWithEqualityFn } from 'zustand/traditional'; import { - getFitViewNodes, - fitView as fitViewSystem, adoptUserNodes, updateAbsolutePositions, panBy as panBySystem, @@ -15,11 +13,12 @@ import { initialConnection, NodeOrigin, CoordinateExtent, + fitViewport, } from '@xyflow/system'; import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; import getInitialState from './initialState'; -import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams, FitViewOptions } from '../types'; +import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams } from '../types'; const createStore = ({ nodes, @@ -46,7 +45,7 @@ const createStore = ({ (set, get) => ({ ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), setNodes: (nodes: Node[]) => { - const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get(); + const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued, panZoom } = get(); /* * setNodes() is called exclusively in response to user actions: * - either when the `` prop is updated in the controlled ReactFlow setup, @@ -55,14 +54,35 @@ const createStore = ({ * When this happens, we take the note objects passed by the user and extend them with fields * relevant for internal React Flow operations. */ - adoptUserNodes(nodes, nodeLookup, parentLookup, { + + const nodesInitialized = adoptUserNodes(nodes, nodeLookup, parentLookup, { nodeOrigin, nodeExtent, elevateNodesOnSelect, checkEquality: true, }); - set({ nodes }); + let viewportFitted = false; + if (fitViewQueued && nodesInitialized && panZoom) { + const { fitViewOptions, width, height, minZoom, maxZoom } = get(); + viewportFitted = fitViewport( + { + nodes: nodeLookup, + width, + height, + panZoom, + minZoom, + maxZoom, + }, + fitViewOptions + ); + } + + if (viewportFitted) { + set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + } else { + set({ nodes }); + } }, setEdges: (edges: Edge[]) => { const { connectionLookup, edgeLookup } = get(); @@ -88,20 +108,8 @@ const createStore = ({ * changes its dimensions, this function is called to measure the * new dimensions and update the nodes. */ - updateNodeInternals: (updates, params = { triggerFitView: true }) => { - const { - triggerNodeChanges, - nodeLookup, - parentLookup, - fitViewOnInit, - fitViewDone, - fitViewOnInitOptions, - domNode, - nodeOrigin, - nodeExtent, - debug, - fitViewSync, - } = get(); + updateNodeInternals: (updates) => { + const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug } = get(); const { changes, updatedInternals } = updateNodeInternalsSystem( updates, @@ -118,29 +126,8 @@ const createStore = ({ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent }); - 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, - }); - } - - /* - * 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({}); - } + // we always want to trigger useStore calls whenever updateNodeInternals is called + set({}); if (changes?.length > 0) { if (debug) { @@ -332,54 +319,6 @@ const createStore = ({ return panBySystem({ delta, panZoom, transform, translateExtent, width, height }); }, - fitView: (options?: FitViewOptions): Promise => { - const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get(); - - if (!panZoom) { - return Promise.resolve(false); - } - - const fitViewNodes = getFitViewNodes(nodeLookup, options); - - return fitViewSystem( - { - nodes: fitViewNodes, - width, - height, - panZoom, - minZoom, - maxZoom, - }, - options - ); - }, - /* - * we can't call an asnychronous function in updateNodeInternals - * for that we created this sync version of fitView - */ - fitViewSync: (options?: FitViewOptions): boolean => { - const { panZoom, width, height, minZoom, maxZoom, nodeLookup } = get(); - - if (!panZoom) { - return false; - } - - const fitViewNodes = getFitViewNodes(nodeLookup, options); - - fitViewSystem( - { - nodes: fitViewNodes, - width, - height, - panZoom, - minZoom, - maxZoom, - }, - options - ); - - return fitViewNodes.size > 0; - }, cancelConnection: () => { set({ connection: { ...initialConnection }, diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index af52f2a2..9005c99f 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -104,13 +104,13 @@ const getInitialState = ({ elementsSelectable: true, elevateNodesOnSelect: true, elevateEdgesOnSelect: false, - fitViewOnInit: false, - fitViewDone: false, - fitViewOnInitOptions: undefined, selectNodesOnDrag: true, multiSelectionActive: false, + fitViewQueued: false, + fitViewOptions: undefined, + connection: { ...initialConnection }, connectionClickStartHandle: null, connectOnClick: true, diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 8b78e77b..45dc93c1 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -109,7 +109,7 @@ export type FitViewParams = FitViewParamsBase = FitViewOptionsBase; -export type FitView = (fitViewOptions?: FitViewOptions) => Promise; +export type FitView = (fitViewOptions?: FitViewOptions) => void; export type OnInit = ( reactFlowInstance: ReactFlowInstance ) => void; @@ -156,17 +156,6 @@ export type ViewportHelperFunctions = { * @returns Viewport */ getViewport: GetViewport; - /** - * Fits the view. - * - * @param options.padding - optional padding - * @param options.includeHiddenNodes - optional includeHiddenNodes - * @param options.minZoom - optional minZoom - * @param options.maxZoom - optional maxZoom - * @param options.duration - optional duration. If set, a transition will be applied - * @param options.nodes - optional nodes to fit the view to - */ - fitView: FitView; /** * Sets the center of the view to the given position. * diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts index fce67ec5..7aa615f5 100644 --- a/packages/react/src/types/instance.ts +++ b/packages/react/src/types/instance.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-namespace */ import type { HandleConnection, HandleType, NodeConnection, Rect, Viewport } from '@xyflow/system'; -import type { Node, Edge, ViewportHelperFunctions, InternalNode } from '.'; +import type { Node, Edge, ViewportHelperFunctions, InternalNode, FitView } from '.'; export type ReactFlowJsonObject = { nodes: NodeType[]; @@ -217,6 +217,17 @@ export type GeneralHelpers NodeConnection[]; + // /** + // * Fits the view. + // * + // * @param options.padding - optional padding + // * @param options.includeHiddenNodes - optional includeHiddenNodes + // * @param options.minZoom - optional minZoom + // * @param options.maxZoom - optional maxZoom + // * @param options.duration - optional duration. If set, a transition will be applied + // * @param options.nodes - optional nodes to fit the view to + // */ + fitView: FitView; }; /** * The `ReactFlowInstance` provides a collection of methods to query and manipulate diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index e0ec76fa..10814ecf 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -119,9 +119,8 @@ export type ReactFlowStore; onEdgesDelete?: OnEdgesDelete; @@ -168,8 +167,6 @@ export type ReactFlowActions = { triggerNodeChanges: (changes: NodeChange[]) => void; triggerEdgeChanges: (changes: EdgeChange[]) => void; panBy: PanBy; - fitView: (options?: FitViewOptions) => Promise; - fitViewSync: (options?: FitViewOptions) => boolean; setPaneClickDistance: (distance: number) => void; }; diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 9720e8c5..84738faf 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -333,10 +333,10 @@ export const getConnectedEdges = nodeIds.has(edge.source) || nodeIds.has(edge.target)); }; -export function getFitViewNodes< +function getFitViewNodes< Params extends NodeLookup>, Options extends FitViewOptionsBase ->(nodeLookup: Params, options?: Pick) { +>(nodeLookup: Params, options?: Options) { const fitViewNodes: NodeLookup = new Map(); const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null; @@ -351,15 +351,21 @@ export function getFitViewNodes< return fitViewNodes; } -export async function fitView, Options extends FitViewOptionsBase>( +export function fitViewport, Options extends FitViewOptionsBase>( { nodes, width, height, panZoom, minZoom, maxZoom }: Params, options?: Omit -): Promise { +): boolean { if (nodes.size === 0) { - return Promise.resolve(false); + return true; } - const bounds = getInternalNodesBounds(nodes); + if (!panZoom) { + return false; + } + + const nodesToFit = getFitViewNodes(nodes, options); + + const bounds = getInternalNodesBounds(nodesToFit); const viewport = getViewportForBounds( bounds, @@ -370,9 +376,9 @@ export async function fitView, Option options?.padding ?? 0.1 ); - await panZoom.setViewport(viewport, { duration: options?.duration }); + panZoom.setViewport(viewport, { duration: options?.duration }); - return Promise.resolve(true); + return true; } /** diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index a9d13316..03b4249c 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -85,9 +85,10 @@ export function adoptUserNodes( nodeLookup: NodeLookup>, parentLookup: ParentLookup>, options?: UpdateNodesOptions -) { +): boolean { const _options = mergeObjects(adoptUserNodesDefaultOptions, options); + let nodesInitialized = true; const tmpLookup = new Map(nodeLookup); const selectedNodeZ: number = _options?.elevateNodesOnSelect ? 1000 : 0; @@ -123,10 +124,16 @@ export function adoptUserNodes( nodeLookup.set(userNode.id, internalNode); } + if (!internalNode.measured || !internalNode.measured.width || !internalNode.measured.height) { + nodesInitialized = false; + } + if (userNode.parentId) { updateChildNode(internalNode, nodeLookup, parentLookup, options); } } + + return nodesInitialized; } function updateParentLookup( From f208223400f725dcd1dfac98dc9800e8a9bd38bd Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 15:00:44 +0100 Subject: [PATCH 052/157] Add back promise resolution for transitioning on fitView --- packages/react/src/hooks/useReactFlow.ts | 6 ++++-- packages/react/src/store/index.ts | 12 ++++++------ packages/react/src/store/initialState.ts | 1 + packages/react/src/types/general.ts | 2 +- packages/react/src/types/store.ts | 1 + packages/system/src/utils/graph.ts | 17 ++++++++--------- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index 63b9df86..b67ef0d3 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -279,9 +279,11 @@ export function useReactFlow | undefined) => { - store.setState({ fitViewQueued: true, fitViewOptions: options }); + fitView: async (options: FitViewOptions | undefined) => { + const fitViewResolver = store.getState().fitViewResolver ?? Promise.withResolvers(); + store.setState({ fitViewQueued: true, fitViewOptions: options, fitViewResolver }); batchContext.nodeQueue.push((nodes) => [...nodes]); + return fitViewResolver.promise; }, }; }, []); diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 64d1b405..909d8572 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -62,10 +62,9 @@ const createStore = ({ checkEquality: true, }); - let viewportFitted = false; if (fitViewQueued && nodesInitialized && panZoom) { - const { fitViewOptions, width, height, minZoom, maxZoom } = get(); - viewportFitted = fitViewport( + const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); + const fitViewPromise = fitViewport( { nodes: nodeLookup, width, @@ -76,9 +75,10 @@ const createStore = ({ }, fitViewOptions ); - } - - if (viewportFitted) { + fitViewPromise.then((value) => { + fitViewResolver?.resolve(value); + set({ fitViewResolver: null }); + }); set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); } else { set({ nodes }); diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index 9005c99f..c63c9e9c 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -110,6 +110,7 @@ const getInitialState = ({ fitViewQueued: false, fitViewOptions: undefined, + fitViewResolver: null, connection: { ...initialConnection }, connectionClickStartHandle: null, diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 45dc93c1..11021b3a 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -109,7 +109,7 @@ export type FitViewParams = FitViewParamsBase = FitViewOptionsBase; -export type FitView = (fitViewOptions?: FitViewOptions) => void; +export type FitView = (fitViewOptions?: FitViewOptions) => Promise; export type OnInit = ( reactFlowInstance: ReactFlowInstance ) => void; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index 10814ecf..efd9d957 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -121,6 +121,7 @@ export type ReactFlowStore | null; onNodesDelete?: OnNodesDelete; onEdgesDelete?: OnEdgesDelete; diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 84738faf..e14f81cd 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -351,16 +351,15 @@ function getFitViewNodes< return fitViewNodes; } -export function fitViewport, Options extends FitViewOptionsBase>( +export async function fitViewport< + Params extends FitViewParamsBase, + Options extends FitViewOptionsBase +>( { nodes, width, height, panZoom, minZoom, maxZoom }: Params, options?: Omit -): boolean { +): Promise { if (nodes.size === 0) { - return true; - } - - if (!panZoom) { - return false; + return Promise.resolve(true); } const nodesToFit = getFitViewNodes(nodes, options); @@ -376,9 +375,9 @@ export function fitViewport, Options options?.padding ?? 0.1 ); - panZoom.setViewport(viewport, { duration: options?.duration }); + await panZoom.setViewport(viewport, { duration: options?.duration }); - return true; + return Promise.resolve(true); } /** From c98b6c01f918a8ad63dee790e172a40951a56dd6 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 15:16:12 +0100 Subject: [PATCH 053/157] Add comments --- packages/react/src/hooks/useReactFlow.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index b67ef0d3..a02cbb55 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -280,9 +280,14 @@ export function useReactFlow | undefined) => { + // We either create a new Promise or reuse the existing one + // Even if fitView is called multiple times in a row, we only end up with a single Promise const fitViewResolver = store.getState().fitViewResolver ?? Promise.withResolvers(); + + // We schedule a fitView by setting fitViewQueued and triggering a setNodes store.setState({ fitViewQueued: true, fitViewOptions: options, fitViewResolver }); batchContext.nodeQueue.push((nodes) => [...nodes]); + return fitViewResolver.promise; }, }; From 502a2405601284871667c2f84142fa3ace40253e Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 16:20:05 +0100 Subject: [PATCH 054/157] updated typescript, implemented for svelte flow --- examples/react/package.json | 2 +- examples/svelte/package.json | 2 +- .../src/routes/examples/overview/+page.svelte | 2 +- package.json | 2 +- packages/react/package.json | 2 +- packages/svelte/package.json | 2 +- .../container/SvelteFlow/SvelteFlow.svelte | 2 +- packages/svelte/src/lib/store/index.ts | 69 ++----- .../svelte/src/lib/store/initial-store.ts | 41 ++++- packages/svelte/src/lib/store/utils.ts | 48 ++++- packages/system/package.json | 2 +- packages/system/src/utils/store.ts | 5 +- pnpm-lock.yaml | 173 +++++++----------- tooling/rollup-config/package.json | 2 +- 14 files changed, 167 insertions(+), 187 deletions(-) diff --git a/examples/react/package.json b/examples/react/package.json index ecbcb09f..31099a74 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -37,7 +37,7 @@ "cypress": "13.6.6", "cypress-real-events": "1.12.0", "start-server-and-test": "^2.0.2", - "typescript": "5.2.2", + "typescript": "5.4.5", "vite": "4.5.0" } } diff --git a/examples/svelte/package.json b/examples/svelte/package.json index e8c221ae..cfd2ecea 100644 --- a/examples/svelte/package.json +++ b/examples/svelte/package.json @@ -24,7 +24,7 @@ "svelte": "^4.2.12", "svelte-check": "^3.6.6", "tslib": "^2.6.2", - "typescript": "^5.2.2", + "typescript": "^5.4.5", "vite": "^5.2.12" }, "type": "module", diff --git a/examples/svelte/src/routes/examples/overview/+page.svelte b/examples/svelte/src/routes/examples/overview/+page.svelte index 2dd57734..21ad6f89 100644 --- a/examples/svelte/src/routes/examples/overview/+page.svelte +++ b/examples/svelte/src/routes/examples/overview/+page.svelte @@ -198,7 +198,7 @@ attributionPosition={'top-center'} deleteKey={['Backspace', 'd']} > - + xy console.log('control button')} >log(); - if (!panZoom || !domNode) { - return Promise.resolve(false); - } + // We schedule a fitView by setting fitViewQueued and triggering a setNodes + store.fitViewQueued.set(true); + store.fitViewOptions.set(options); + store.fitViewResolver.set(fitViewResolver); + store.nodes.set(get(store.nodes)); - const { width, height } = getDimensions(domNode); - - const fitViewNodes = getFitViewNodes(get(store.nodeLookup), options); - - return fitViewSystem( - { - nodes: fitViewNodes, - width, - height, - minZoom: get(store.minZoom), - maxZoom: get(store.maxZoom), - panZoom - }, - options - ); - } - - function fitViewSync(options?: FitViewOptions) { - const panZoom = get(store.panZoom); - - if (!panZoom) { - return false; - } - - const fitViewNodes = getFitViewNodes(get(store.nodeLookup), options); - - fitViewSystem( - { - nodes: fitViewNodes, - width: get(store.width), - height: get(store.height), - minZoom: get(store.minZoom), - maxZoom: get(store.maxZoom), - panZoom - }, - options - ); - - return fitViewNodes.size > 0; + return fitViewResolver.promise; } function zoomBy(factor: number, options?: ViewportHelperFunctionOptions) { @@ -395,7 +349,6 @@ export function createStore({ } function reset() { - store.fitViewOnInitDone.set(false); store.selectionRect.set(null); store.selectionRectMode.set(null); store.snapGrid.set(null); diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index 142460a7..3b0064a8 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -112,9 +112,32 @@ export const getInitialStore = ({ viewport = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1); } + const fitViewQueued = writable(false); + const fitViewOptions = writable(undefined); + const fitViewResolver = writable | null>(null); + const panZoom = writable(null); + const widthStore = writable(500); + const heightStore = writable(500); + const minZoom = writable(0.5); + const maxZoom = writable(2); + return { flowId: writable(null), - nodes: createNodesStore(nodes, nodeLookup, parentLookup, storeNodeOrigin, storeNodeExtent), + nodes: createNodesStore( + nodes, + nodeLookup, + parentLookup, + storeNodeOrigin, + storeNodeExtent, + fitViewQueued, + fitViewOptions, + fitViewResolver, + panZoom, + widthStore, + heightStore, + minZoom, + maxZoom + ), nodeLookup: readable>(nodeLookup), parentLookup: readable>(parentLookup), edgeLookup: readable>(edgeLookup), @@ -122,20 +145,20 @@ export const getInitialStore = ({ edges: createEdgesStore(edges, connectionLookup, edgeLookup), visibleEdges: readable([]), connectionLookup: readable(connectionLookup), - height: writable(500), - width: writable(500), - minZoom: writable(0.5), - maxZoom: writable(2), + width: widthStore, + height: heightStore, + minZoom, + maxZoom, nodeOrigin: writable(storeNodeOrigin), nodeDragThreshold: writable(1), nodeExtent: writable(storeNodeExtent), translateExtent: writable(infiniteExtent), autoPanOnNodeDrag: writable(true), autoPanOnConnect: writable(true), - fitViewOnInit: writable(false), - fitViewOnInitDone: writable(false), - fitViewOptions: writable(undefined), - panZoom: writable(null), + fitViewQueued, + fitViewOptions, + fitViewResolver, + panZoom, snapGrid: writable(null), dragging: writable(false), selectionRect: writable(null), diff --git a/packages/svelte/src/lib/store/utils.ts b/packages/svelte/src/lib/store/utils.ts index 30af8f73..0d453c45 100644 --- a/packages/svelte/src/lib/store/utils.ts +++ b/packages/svelte/src/lib/store/utils.ts @@ -17,10 +17,18 @@ import { type ParentLookup, type NodeOrigin, infiniteExtent, - type CoordinateExtent + type CoordinateExtent, + fitViewport } from '@xyflow/system'; -import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, InternalNode, Node } from '$lib/types'; +import type { + DefaultEdgeOptions, + DefaultNodeOptions, + Edge, + FitViewOptions, + InternalNode, + Node +} from '$lib/types'; // we need to sync the user nodes and the internal nodes so that the user can receive the updates // made by Svelte Flow (like dragging or selecting a node). @@ -134,7 +142,15 @@ export const createNodesStore = ( nodeLookup: NodeLookup, parentLookup: ParentLookup, nodeOrigin: NodeOrigin = [0, 0], - nodeExtent: CoordinateExtent = infiniteExtent + nodeExtent: CoordinateExtent = infiniteExtent, + fitViewQueued: Writable, + fitViewOptions: Writable, + fitViewResolver: Writable | null>, + panZoom: Writable, + width: Writable, + height: Writable, + minZoom: Writable, + maxZoom: Writable ): { subscribe: (this: void, run: Subscriber) => Unsubscriber; update: (this: void, updater: Updater) => void; @@ -148,7 +164,7 @@ export const createNodesStore = ( let elevateNodesOnSelect = true; const _set = (nds: Node[]): Node[] => { - adoptUserNodes(nds, nodeLookup, parentLookup, { + const nodesInitialized = adoptUserNodes(nds, nodeLookup, parentLookup, { elevateNodesOnSelect, nodeOrigin, nodeExtent, @@ -156,6 +172,30 @@ export const createNodesStore = ( checkEquality: false }); + console.log(nodesInitialized); + + if (get(fitViewQueued) && nodesInitialized && get(panZoom)) { + console.log('trying'); + const fitViewPromise = fitViewport( + { + nodes: nodeLookup, + width: get(width), + height: get(height), + panZoom: get(panZoom)!, + minZoom: get(minZoom), + maxZoom: get(maxZoom) + }, + get(fitViewOptions) + ); + fitViewPromise.then((value) => { + get(fitViewResolver)?.resolve(value); + fitViewResolver.set(null); + }); + + fitViewQueued.set(false); + fitViewOptions.set(undefined); + } + value = nds; set(value); diff --git a/packages/system/package.json b/packages/system/package.json index 9f45b7ef..f23d4c73 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -63,7 +63,7 @@ "@xyflow/eslint-config": "workspace:*", "@xyflow/rollup-config": "workspace:*", "@xyflow/tsconfig": "workspace:*", - "typescript": "5.1.3" + "typescript": "5.4.5" }, "rollup": { "globals": { diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index 03b4249c..14fc710a 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -124,7 +124,10 @@ export function adoptUserNodes( nodeLookup.set(userNode.id, internalNode); } - if (!internalNode.measured || !internalNode.measured.width || !internalNode.measured.height) { + if ( + (!internalNode.measured || !internalNode.measured.width || !internalNode.measured.height) && + !internalNode.hidden + ) { nodesInitialized = false; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22541966..bb3a0689 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,8 +42,8 @@ importers: specifier: ^2.0.3 version: 2.0.3 typescript: - specifier: 5.1.3 - version: 5.1.3 + specifier: 5.4.5 + version: 5.4.5 examples/astro-xyflow: dependencies: @@ -145,8 +145,8 @@ importers: specifier: ^2.0.2 version: 2.0.2 typescript: - specifier: 5.2.2 - version: 5.2.2 + specifier: 5.4.5 + version: 5.4.5 vite: specifier: 4.5.0 version: 4.5.0(@types/node@20.14.6)(terser@5.31.0) @@ -171,10 +171,10 @@ importers: version: 2.5.10(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.12)(vite@5.2.12(@types/node@20.14.6)(terser@5.31.0)))(svelte@4.2.12)(vite@5.2.12(@types/node@20.14.6)(terser@5.31.0)) '@typescript-eslint/eslint-plugin': specifier: ^6.10.0 - version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2))(eslint@8.53.0)(typescript@5.2.2) + version: 6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.4.5))(eslint@8.53.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^6.10.0 - version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) + version: 6.10.0(eslint@8.53.0)(typescript@5.4.5) eslint: specifier: ^8.53.0 version: 8.53.0 @@ -200,8 +200,8 @@ importers: specifier: ^2.6.2 version: 2.6.2 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.4.5 + version: 5.4.5 vite: specifier: ^5.2.12 version: 5.2.12(@types/node@20.14.6)(terser@5.31.0) @@ -267,8 +267,8 @@ importers: specifier: ^18.2.0 version: 18.2.0 typescript: - specifier: 5.1.3 - version: 5.1.3 + specifier: 5.4.5 + version: 5.4.5 packages/svelte: dependencies: @@ -290,13 +290,13 @@ importers: version: 2.5.4(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.12)(vite@5.3.2(@types/node@20.14.6)(terser@5.31.0)))(svelte@4.2.12)(vite@5.3.2(@types/node@20.14.6)(terser@5.31.0)) '@sveltejs/package': specifier: ^2.3.0 - version: 2.3.0(svelte@4.2.12)(typescript@5.4.2) + version: 2.3.0(svelte@4.2.12)(typescript@5.4.5) '@typescript-eslint/eslint-plugin': specifier: ^7.2.0 - version: 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.2))(eslint@8.57.0)(typescript@5.4.2) + version: 7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^7.2.0 - version: 7.2.0(eslint@8.57.0)(typescript@5.4.2) + version: 7.2.0(eslint@8.57.0)(typescript@5.4.5) autoprefixer: specifier: ^10.4.18 version: 10.4.18(postcss@8.4.35) @@ -350,13 +350,13 @@ importers: version: 0.33.1(svelte@4.2.12) svelte-preprocess: specifier: ^5.1.3 - version: 5.1.3(@babel/core@7.24.7)(postcss-load-config@5.0.2(postcss@8.4.35))(postcss@8.4.35)(svelte@4.2.12)(typescript@5.4.2) + version: 5.1.3(@babel/core@7.24.7)(postcss-load-config@5.0.2(postcss@8.4.35))(postcss@8.4.35)(svelte@4.2.12)(typescript@5.4.5) tslib: specifier: ^2.6.2 version: 2.6.2 typescript: - specifier: 5.4.2 - version: 5.4.2 + specifier: 5.4.5 + version: 5.4.5 packages/system: dependencies: @@ -395,8 +395,8 @@ importers: specifier: workspace:* version: link:../../tooling/tsconfig typescript: - specifier: 5.1.3 - version: 5.1.3 + specifier: 5.4.5 + version: 5.4.5 tests/playwright: dependencies: @@ -463,7 +463,7 @@ importers: version: 0.4.4(rollup@4.18.0) '@rollup/plugin-typescript': specifier: 11.1.6 - version: 11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.2) + version: 11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.5) rollup: specifier: ^4.18.0 version: 4.18.0 @@ -471,8 +471,8 @@ importers: specifier: ^2.2.4 version: 2.2.4(rollup@4.18.0) typescript: - specifier: ^5.1.3 - version: 5.4.2 + specifier: ^5.4.5 + version: 5.4.5 tooling/tsconfig: {} @@ -6300,21 +6300,6 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript@5.1.3: - resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -7884,11 +7869,11 @@ snapshots: optionalDependencies: rollup: 4.18.0 - '@rollup/plugin-typescript@11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.2)': + '@rollup/plugin-typescript@11.1.6(rollup@4.18.0)(tslib@2.6.2)(typescript@5.4.5)': dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.18.0) resolve: 1.22.8 - typescript: 5.4.2 + typescript: 5.4.5 optionalDependencies: rollup: 4.18.0 tslib: 2.6.2 @@ -8009,14 +7994,14 @@ snapshots: tiny-glob: 0.2.9 vite: 5.3.2(@types/node@20.14.6)(terser@5.31.0) - '@sveltejs/package@2.3.0(svelte@4.2.12)(typescript@5.4.2)': + '@sveltejs/package@2.3.0(svelte@4.2.12)(typescript@5.4.5)': dependencies: chokidar: 3.6.0 kleur: 4.1.5 sade: 1.8.1 semver: 7.6.0 svelte: 4.2.12 - svelte2tsx: 0.7.3(svelte@4.2.12)(typescript@5.4.2) + svelte2tsx: 0.7.3(svelte@4.2.12)(typescript@5.4.5) transitivePeerDependencies: - typescript @@ -8319,13 +8304,13 @@ snapshots: '@types/node': 18.7.16 optional: true - '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2))(eslint@8.53.0)(typescript@5.2.2)': + '@typescript-eslint/eslint-plugin@6.10.0(@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.4.5))(eslint@8.53.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/parser': 6.10.0(eslint@8.53.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 6.10.0 - '@typescript-eslint/type-utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/type-utils': 6.10.0(eslint@8.53.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 @@ -8333,19 +8318,19 @@ snapshots: ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.2.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.2))(eslint@8.57.0)(typescript@5.4.2)': + '@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.2.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 @@ -8353,9 +8338,9 @@ snapshots: ignore: 5.3.0 natural-compare: 1.4.0 semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.4.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.4.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8376,29 +8361,29 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.2.2)': + '@typescript-eslint/parser@6.10.0(eslint@8.53.0)(typescript@5.4.5)': dependencies: '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.10.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 optionalDependencies: - typescript: 5.2.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.2)': + '@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@typescript-eslint/scope-manager': 7.2.0 '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.2.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 optionalDependencies: - typescript: 5.4.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8429,27 +8414,27 @@ snapshots: '@typescript-eslint/types': 8.23.0 '@typescript-eslint/visitor-keys': 8.23.0 - '@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': + '@typescript-eslint/type-utils@6.10.0(eslint@8.53.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.4.5) + '@typescript-eslint/utils': 6.10.0(eslint@8.53.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) eslint: 8.53.0 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.2.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@7.2.0(eslint@8.57.0)(typescript@5.4.2)': + '@typescript-eslint/type-utils@7.2.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.5) + '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.5) debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 - ts-api-utils: 1.0.3(typescript@5.4.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.4.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8470,7 +8455,7 @@ snapshots: '@typescript-eslint/types@8.23.0': {} - '@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)': + '@typescript-eslint/typescript-estree@6.10.0(typescript@5.4.5)': dependencies: '@typescript-eslint/types': 6.10.0 '@typescript-eslint/visitor-keys': 6.10.0 @@ -8478,13 +8463,13 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.2.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.2.0(typescript@5.4.2)': + '@typescript-eslint/typescript-estree@7.2.0(typescript@5.4.5)': dependencies: '@typescript-eslint/types': 7.2.0 '@typescript-eslint/visitor-keys': 7.2.0 @@ -8493,9 +8478,9 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.0 - ts-api-utils: 1.0.3(typescript@5.4.2) + ts-api-utils: 1.0.3(typescript@5.4.5) optionalDependencies: - typescript: 5.4.2 + typescript: 5.4.5 transitivePeerDependencies: - supports-color @@ -8513,28 +8498,28 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.2.2)': + '@typescript-eslint/utils@6.10.0(eslint@8.53.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 6.10.0 '@typescript-eslint/types': 6.10.0 - '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.10.0(typescript@5.4.5) eslint: 8.53.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.2.0(eslint@8.57.0)(typescript@5.4.2)': + '@typescript-eslint/utils@7.2.0(eslint@8.57.0)(typescript@5.4.5)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.6 '@typescript-eslint/scope-manager': 7.2.0 '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) + '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.5) eslint: 8.57.0 semver: 7.6.0 transitivePeerDependencies: @@ -13430,20 +13415,6 @@ snapshots: dependencies: svelte: 4.2.12 - svelte-preprocess@5.1.3(@babel/core@7.24.7)(postcss-load-config@5.0.2(postcss@8.4.35))(postcss@8.4.35)(svelte@4.2.12)(typescript@5.4.2): - dependencies: - '@types/pug': 2.0.10 - detect-indent: 6.1.0 - magic-string: 0.30.8 - sorcery: 0.11.0 - strip-indent: 3.0.0 - svelte: 4.2.12 - optionalDependencies: - '@babel/core': 7.24.7 - postcss: 8.4.35 - postcss-load-config: 5.0.2(postcss@8.4.35) - typescript: 5.4.2 - svelte-preprocess@5.1.3(@babel/core@7.24.7)(postcss-load-config@5.0.2(postcss@8.4.35))(postcss@8.4.35)(svelte@4.2.12)(typescript@5.4.5): dependencies: '@types/pug': 2.0.10 @@ -13465,12 +13436,12 @@ snapshots: svelte: 4.2.1 typescript: 5.4.5 - svelte2tsx@0.7.3(svelte@4.2.12)(typescript@5.4.2): + svelte2tsx@0.7.3(svelte@4.2.12)(typescript@5.4.5): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 svelte: 4.2.12 - typescript: 5.4.2 + typescript: 5.4.5 svelte@4.2.1: dependencies: @@ -13608,13 +13579,9 @@ snapshots: trough@2.1.0: {} - ts-api-utils@1.0.3(typescript@5.2.2): + ts-api-utils@1.0.3(typescript@5.4.5): dependencies: - typescript: 5.2.2 - - ts-api-utils@1.0.3(typescript@5.4.2): - dependencies: - typescript: 5.4.2 + typescript: 5.4.5 ts-api-utils@2.0.1(typescript@5.4.5): dependencies: @@ -13782,12 +13749,6 @@ snapshots: possible-typed-array-names: 1.0.0 reflect.getprototypeof: 1.0.10 - typescript@5.1.3: {} - - typescript@5.2.2: {} - - typescript@5.4.2: {} - typescript@5.4.5: {} ultrahtml@1.5.2: {} diff --git a/tooling/rollup-config/package.json b/tooling/rollup-config/package.json index c8871f61..d04d3d93 100644 --- a/tooling/rollup-config/package.json +++ b/tooling/rollup-config/package.json @@ -14,6 +14,6 @@ "@rollup/plugin-typescript": "11.1.6", "rollup": "^4.18.0", "rollup-plugin-peer-deps-external": "^2.2.4", - "typescript": "^5.1.3" + "typescript": "^5.4.5" } } From cb685281d0eaf03e9833271c31f92b1d143af2fe Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 16:22:43 +0100 Subject: [PATCH 055/157] add changeset --- .changeset/poor-poems-visit.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/poor-poems-visit.md diff --git a/.changeset/poor-poems-visit.md b/.changeset/poor-poems-visit.md new file mode 100644 index 00000000..4aeb827d --- /dev/null +++ b/.changeset/poor-poems-visit.md @@ -0,0 +1,7 @@ +--- +'@xyflow/react': minor +'@xyflow/svelte': patch +'@xyflow/system': patch +--- + +Fix fitView not working when adding new nodes From cd03c4619610c9426ce46b373975cfddc5e54417 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 5 Mar 2025 17:38:30 +0100 Subject: [PATCH 056/157] Add pixel units and left and right padding options for fitView --- packages/system/src/types/general.ts | 3 ++- packages/system/src/utils/general.ts | 12 +++++++++--- packages/system/src/utils/graph.ts | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 8ac3f9e9..1f6b2ecf 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -95,7 +95,8 @@ export type FitViewParamsBase = { * @inline */ export type FitViewOptionsBase = { - padding?: number; + padding?: number | [number, number]; + paddingUnit?: 'px' | '%'; includeHiddenNodes?: boolean; minZoom?: number; maxZoom?: number; diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 32c339e5..90ff64fa 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -195,10 +195,16 @@ export const getViewportForBounds = ( height: number, minZoom: number, maxZoom: number, - padding: number + padding: number | [number, number], + paddingUnit: 'px' | '%' ): Viewport => { - const xZoom = width / (bounds.width * (1 + padding)); - const yZoom = height / (bounds.height * (1 + padding)); + const [paddingX, paddingY] = Array.isArray(padding) ? [padding[0], padding[1]] : [padding, padding]; + + const isPixelPadding = paddingUnit === 'px'; + + const xZoom = width / (isPixelPadding ? bounds.width + paddingX : bounds.width * (1 + paddingX)); + const yZoom = height / (isPixelPadding ? bounds.height + paddingY : bounds.height * (1 + paddingY)); + const zoom = Math.min(xZoom, yZoom); const clampedZoom = clamp(zoom, minZoom, maxZoom); const boundsCenterX = bounds.x + bounds.width / 2; diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index e14f81cd..930c4adb 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -372,7 +372,8 @@ export async function fitViewport< height, options?.minZoom ?? minZoom, options?.maxZoom ?? maxZoom, - options?.padding ?? 0.1 + options?.padding ?? 0.1, + options?.paddingUnit ?? '%' ); await panZoom.setViewport(viewport, { duration: options?.duration }); From 8da1748a6ad5cdde9f03737ff786bd29c9c968de Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 17 Mar 2025 14:34:25 +0100 Subject: [PATCH 057/157] chore(changeset): add --- .changeset/unlucky-lobsters-refuse.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/unlucky-lobsters-refuse.md diff --git a/.changeset/unlucky-lobsters-refuse.md b/.changeset/unlucky-lobsters-refuse.md new file mode 100644 index 00000000..e98d4c08 --- /dev/null +++ b/.changeset/unlucky-lobsters-refuse.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Release key even when an inout field is focused From 8ff900c0cffa2f84bef0fb9b1e950b9ee34ace90 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 17 Mar 2025 14:50:32 +0100 Subject: [PATCH 058/157] feat(panel): add center-left and center-right positions #5082 --- packages/system/src/styles/init.css | 17 ++++++++++++++--- packages/system/src/types/general.ts | 10 +++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/system/src/styles/init.css b/packages/system/src/styles/init.css index e167c53f..b0651116 100644 --- a/packages/system/src/styles/init.css +++ b/packages/system/src/styles/init.css @@ -278,6 +278,14 @@ svg.xy-flow__connectionline { bottom: 0; } + &.top, + &.bottom { + &.center { + left: 50%; + transform: translateX(-50%); + } + } + &.left { left: 0; } @@ -286,9 +294,12 @@ svg.xy-flow__connectionline { right: 0; } - &.center { - left: 50%; - transform: translateX(-50%); + &.left, + &.right { + &.center { + top: 50%; + transform: translateY(-50%); + } } } diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 8ac3f9e9..fc92bc7e 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -169,7 +169,15 @@ export type UpdateNodeInternals = (nodeId: string | string[]) => void; * * @public */ -export type PanelPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; +export type PanelPosition = + | 'top-left' + | 'top-center' + | 'top-right' + | 'bottom-left' + | 'bottom-center' + | 'bottom-right' + | 'center-left' + | 'center-right'; export type ProOptions = { account?: string; From a79f30b3dd7c8ff6400c8d22214b2c2282e5bac1 Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 17 Mar 2025 14:52:09 +0100 Subject: [PATCH 059/157] chore(changeset): add --- .changeset/witty-toys-wash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/witty-toys-wash.md diff --git a/.changeset/witty-toys-wash.md b/.changeset/witty-toys-wash.md new file mode 100644 index 00000000..4f2972f6 --- /dev/null +++ b/.changeset/witty-toys-wash.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Add center-left and center-right as a panel position From db4c019fe42d1528f0fd6d816202281603c079fe Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 17 Mar 2025 16:01:22 +0100 Subject: [PATCH 060/157] either trigger fitView after adoptUserNodes or after updateNodeInternals --- examples/react/src/examples/Stress/index.tsx | 16 +++++++-- packages/react/src/store/index.ts | 36 ++++++++++++++++++-- packages/react/src/store/initialState.ts | 2 +- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/examples/react/src/examples/Stress/index.tsx b/examples/react/src/examples/Stress/index.tsx index 9020ddd6..496fd500 100644 --- a/examples/react/src/examples/Stress/index.tsx +++ b/examples/react/src/examples/Stress/index.tsx @@ -12,6 +12,8 @@ import { Controls, Background, Panel, + ReactFlowProvider, + useReactFlow, } from '@xyflow/react'; import { getNodesAndEdges } from './utils'; @@ -22,6 +24,7 @@ const { nodes: initialNodes, edges: initialEdges } = getNodesAndEdges(25, 25); const StressFlow = () => { const [nodes, setNodes] = useState(initialNodes); const [edges, setEdges] = useState(initialEdges); + const { fitView } = useReactFlow(); const onConnect = useCallback((connection: Connection) => { setEdges((eds) => addEdge(connection, eds)); }, []); @@ -191,12 +194,13 @@ const StressFlow = () => { return { ...n, position: { - x: Math.random() * window.innerWidth, - y: Math.random() * window.innerHeight, + x: Math.random() * window.innerWidth * 4, + y: Math.random() * window.innerHeight * 4, }, }; }); }); + fitView(); }; const updateElements = () => { @@ -240,4 +244,10 @@ const StressFlow = () => { ); }; -export default StressFlow; +export default function StressFlowProvider() { + return ( + + + + ); +} diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 909d8572..68d1dd24 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -109,7 +109,17 @@ const createStore = ({ * new dimensions and update the nodes. */ updateNodeInternals: (updates) => { - const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug } = get(); + const { + triggerNodeChanges, + nodeLookup, + parentLookup, + domNode, + nodeOrigin, + nodeExtent, + debug, + panZoom, + fitViewQueued, + } = get(); const { changes, updatedInternals } = updateNodeInternalsSystem( updates, @@ -126,8 +136,28 @@ const createStore = ({ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent }); - // we always want to trigger useStore calls whenever updateNodeInternals is called - set({}); + if (fitViewQueued && panZoom) { + const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); + const fitViewPromise = fitViewport( + { + nodes: nodeLookup, + width, + height, + panZoom, + minZoom, + maxZoom, + }, + fitViewOptions + ); + fitViewPromise.then((value) => { + fitViewResolver?.resolve(value); + set({ fitViewResolver: null }); + }); + set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + } else { + // we always want to trigger useStore calls whenever updateNodeInternals is called + set({}); + } if (changes?.length > 0) { if (debug) { diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index c63c9e9c..8be408b8 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -108,7 +108,7 @@ const getInitialState = ({ multiSelectionActive: false, - fitViewQueued: false, + fitViewQueued: fitView ?? false, fitViewOptions: undefined, fitViewResolver: null, From 254800ab9be8d925573360802947e6dd5226fc76 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 18 Mar 2025 09:09:36 +0100 Subject: [PATCH 061/157] refactor(minimap): do not show hidden nodes #5078 --- .../additional-components/MiniMap/MiniMap.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index c7f1fdce..ad899043 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -15,6 +15,8 @@ import type { MiniMapProps } from './types'; const defaultWidth = 200; const defaultHeight = 150; +const filterHidden = (node: Node) => !node.hidden; + const selector = (s: ReactFlowState) => { const viewBB: Rect = { x: -s.transform[0] / s.transform[2], @@ -25,7 +27,10 @@ const selector = (s: ReactFlowState) => { return { viewBB, - boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup), viewBB) : viewBB, + boundingRect: + s.nodeLookup.size > 0 + ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { filter: filterHidden }), viewBB) + : viewBB, rfId: s.rfId, panZoom: s.panZoom, translateExtent: s.translateExtent, @@ -113,16 +118,16 @@ function MiniMapComponent({ const onSvgClick = onClick ? (event: MouseEvent) => { - const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; - onClick(event, { x, y }); - } + const [x, y] = minimapInstance.current?.pointer(event) || [0, 0]; + onClick(event, { x, y }); + } : undefined; const onSvgNodeClick = onNodeClick ? useCallback((event: MouseEvent, nodeId: string) => { - const node = store.getState().nodeLookup.get(nodeId)!; - onNodeClick(event, node); - }, []) + const node = store.getState().nodeLookup.get(nodeId)!; + onNodeClick(event, node); + }, []) : undefined; return ( From 3ae66142be47e0031981a8560cf6b19c634a2f17 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 18 Mar 2025 09:11:29 +0100 Subject: [PATCH 062/157] refactor(svelte/minimap): do not show hidden nodes --- packages/svelte/src/lib/plugins/Minimap/Minimap.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte index 789dc476..fa8e7703 100644 --- a/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte +++ b/packages/svelte/src/lib/plugins/Minimap/Minimap.svelte @@ -76,7 +76,12 @@ $: { boundingRect = - $nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds($nodeLookup), viewBB) : viewBB; + $nodeLookup.size > 0 + ? getBoundsOfRects( + getInternalNodesBounds($nodeLookup, { filter: (n) => !n.hidden }), + viewBB + ) + : viewBB; $nodes; } From 65825e89a6e2e7591087eb41ac89da4da7095f8f Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 18 Mar 2025 09:12:18 +0100 Subject: [PATCH 063/157] chore(changeset): add --- .changeset/twenty-sloths-reflect.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/twenty-sloths-reflect.md diff --git a/.changeset/twenty-sloths-reflect.md b/.changeset/twenty-sloths-reflect.md new file mode 100644 index 00000000..fda503ae --- /dev/null +++ b/.changeset/twenty-sloths-reflect.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/svelte': patch +--- + +Hidden nodes are not displayed in the mini map anymore From 6acb709bef20c9663e453956567f6e08a553b289 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 18 Mar 2025 09:30:29 +0100 Subject: [PATCH 064/157] extract fitView into action --- packages/react/src/store/index.ts | 89 +++++++++++++------------------ 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 68d1dd24..8b219d27 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -41,11 +41,36 @@ const createStore = ({ nodeOrigin?: NodeOrigin; nodeExtent?: CoordinateExtent; }) => - createWithEqualityFn( - (set, get) => ({ + createWithEqualityFn((set, get) => { + function resolveFitView() { + const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); + + if (!panZoom) { + return; + } + + const fitViewPromise = fitViewport( + { + nodes: nodeLookup, + width, + height, + panZoom, + minZoom, + maxZoom, + }, + fitViewOptions + ); + fitViewPromise.then((value) => { + fitViewResolver?.resolve(value); + set({ fitViewResolver: null }); + }); + set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + } + + return { ...getInitialState({ nodes, edges, width, height, fitView, nodeOrigin, nodeExtent, defaultNodes, defaultEdges }), setNodes: (nodes: Node[]) => { - const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued, panZoom } = get(); + const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect, fitViewQueued } = get(); /* * setNodes() is called exclusively in response to user actions: * - either when the `` prop is updated in the controlled ReactFlow setup, @@ -62,24 +87,8 @@ const createStore = ({ checkEquality: true, }); - if (fitViewQueued && nodesInitialized && panZoom) { - const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); - const fitViewPromise = fitViewport( - { - nodes: nodeLookup, - width, - height, - panZoom, - minZoom, - maxZoom, - }, - fitViewOptions - ); - fitViewPromise.then((value) => { - fitViewResolver?.resolve(value); - set({ fitViewResolver: null }); - }); - set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + if (fitViewQueued && nodesInitialized) { + resolveFitView(); } else { set({ nodes }); } @@ -109,17 +118,8 @@ const createStore = ({ * new dimensions and update the nodes. */ updateNodeInternals: (updates) => { - const { - triggerNodeChanges, - nodeLookup, - parentLookup, - domNode, - nodeOrigin, - nodeExtent, - debug, - panZoom, - fitViewQueued, - } = get(); + const { triggerNodeChanges, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, debug, fitViewQueued } = + get(); const { changes, updatedInternals } = updateNodeInternalsSystem( updates, @@ -136,24 +136,8 @@ const createStore = ({ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin, nodeExtent }); - if (fitViewQueued && panZoom) { - const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); - const fitViewPromise = fitViewport( - { - nodes: nodeLookup, - width, - height, - panZoom, - minZoom, - maxZoom, - }, - fitViewOptions - ); - fitViewPromise.then((value) => { - fitViewResolver?.resolve(value); - set({ fitViewResolver: null }); - }); - set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); + if (fitViewQueued) { + resolveFitView(); } else { // we always want to trigger useStore calls whenever updateNodeInternals is called set({}); @@ -359,8 +343,7 @@ const createStore = ({ }, reset: () => set({ ...getInitialState() }), - }), - Object.is - ); + }; + }, Object.is); export { createStore }; From 8ecf9082f7c3659451cad8db8cc55f72e5bec55c Mon Sep 17 00:00:00 2001 From: moklick Date: Sat, 22 Mar 2025 15:37:04 +0100 Subject: [PATCH 065/157] chore(ts-docs): add annotations for edges --- .../components/EdgeLabelRenderer/index.tsx | 53 ++++++++++--------- .../react/src/components/Edges/BezierEdge.tsx | 27 ++++++++++ .../react/src/components/Edges/EdgeAnchor.tsx | 3 ++ .../react/src/components/Edges/EdgeText.tsx | 36 ++++++------- .../src/components/Edges/SmoothStepEdge.tsx | 27 ++++++++++ .../react/src/components/Edges/StepEdge.tsx | 27 ++++++++++ .../src/components/Edges/StraightEdge.tsx | 25 +++++++++ 7 files changed, 154 insertions(+), 44 deletions(-) diff --git a/packages/react/src/components/EdgeLabelRenderer/index.tsx b/packages/react/src/components/EdgeLabelRenderer/index.tsx index 647811cb..2b603dc3 100644 --- a/packages/react/src/components/EdgeLabelRenderer/index.tsx +++ b/packages/react/src/components/EdgeLabelRenderer/index.tsx @@ -10,37 +10,38 @@ const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__e * Edges are SVG-based. If you want to render more complex labels you can use the * `` component to access a div based renderer. This component * is a portal that renders the label in a `
` that is positioned on top of - * the edges. You can see an example usage of the component in the [edge label renderer](/examples/edges/edge-label-renderer) example. + * the edges. You can see an example usage of the component in the + * [edge label renderer example](/examples/edges/edge-label-renderer). * @public * * @example - *```jsx - *import React from 'react'; - *import { getBezierPath, EdgeLabelRenderer, BaseEdge } from '@xyflow/react'; + * ```jsx + * import React from 'react'; + * import { getBezierPath, EdgeLabelRenderer, BaseEdge } from '@xyflow/react'; * - *export function CustomEdge({ id, data, ...props }) { - * const [edgePath, labelX, labelY] = getBezierPath(props); + * export function CustomEdge({ id, data, ...props }) { + * const [edgePath, labelX, labelY] = getBezierPath(props); * - * return ( - * <> - * - * - *
- * {data.label} - *
- *
- * - * ); - *}; - *``` + * return ( + * <> + * + * + *
+ * {data.label} + *
+ *
+ * + * ); + * }; + * ``` * * @remarks The `` has no pointer events by default. If you want to * add mouse interactions you need to set the style `pointerEvents: all` and add diff --git a/packages/react/src/components/Edges/BezierEdge.tsx b/packages/react/src/components/Edges/BezierEdge.tsx index 482f1fd8..3e84a39b 100644 --- a/packages/react/src/components/Edges/BezierEdge.tsx +++ b/packages/react/src/components/Edges/BezierEdge.tsx @@ -61,7 +61,34 @@ function createBezierEdge(params: { isInternal: boolean }) { ); } +/** + * Component that can be used inside a custom edge to render a bezier curve. + * + * @public + * @example + * + * ```tsx + * import { BezierEdge } from '@xyflow/react'; + * + * function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) { + * return ( + * + * ); + * } + * ``` + */ const BezierEdge = createBezierEdge({ isInternal: false }); + +/** + * @internal + */ const BezierEdgeInternal = createBezierEdge({ isInternal: true }); BezierEdge.displayName = 'BezierEdge'; diff --git a/packages/react/src/components/Edges/EdgeAnchor.tsx b/packages/react/src/components/Edges/EdgeAnchor.tsx index a975eaf5..9ee5f600 100644 --- a/packages/react/src/components/Edges/EdgeAnchor.tsx +++ b/packages/react/src/components/Edges/EdgeAnchor.tsx @@ -27,6 +27,9 @@ export interface EdgeAnchorProps extends SVGAttributes { const EdgeUpdaterClassName = 'react-flow__edgeupdater'; +/** + * @internal + */ export function EdgeAnchor({ position, centerX, diff --git a/packages/react/src/components/Edges/EdgeText.tsx b/packages/react/src/components/Edges/EdgeText.tsx index 2c79f718..9807302a 100644 --- a/packages/react/src/components/Edges/EdgeText.tsx +++ b/packages/react/src/components/Edges/EdgeText.tsx @@ -77,26 +77,26 @@ EdgeTextComponent.displayName = 'EdgeText'; * You can use the `` component as a helper component to display text * within your custom edges. * - *@public + * @public * - *@example - *```jsx - *import { EdgeText } from '@xyflow/react'; + * @example + * ```jsx + * import { EdgeText } from '@xyflow/react'; * - *export function CustomEdgeLabel({ label }) { - * return ( - * - * ); - *} + * export function CustomEdgeLabel({ label }) { + * return ( + * + * ); + * } *``` */ export const EdgeText = memo(EdgeTextComponent); diff --git a/packages/react/src/components/Edges/SmoothStepEdge.tsx b/packages/react/src/components/Edges/SmoothStepEdge.tsx index 1f6bcfd1..8b1475cf 100644 --- a/packages/react/src/components/Edges/SmoothStepEdge.tsx +++ b/packages/react/src/components/Edges/SmoothStepEdge.tsx @@ -62,7 +62,34 @@ function createSmoothStepEdge(params: { isInternal: boolean }) { ); } +/** + * Component that can be used inside a custom edge to render a smooth step edge. + * + * @public + * @example + * + * ```tsx + * import { SmoothStepEdge } from '@xyflow/react'; + * + * function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) { + * return ( + * + * ); + * } + * ``` + */ const SmoothStepEdge = createSmoothStepEdge({ isInternal: false }); + +/** + * @internal + */ const SmoothStepEdgeInternal = createSmoothStepEdge({ isInternal: true }); SmoothStepEdge.displayName = 'SmoothStepEdge'; diff --git a/packages/react/src/components/Edges/StepEdge.tsx b/packages/react/src/components/Edges/StepEdge.tsx index 6385e8f0..cd08758c 100644 --- a/packages/react/src/components/Edges/StepEdge.tsx +++ b/packages/react/src/components/Edges/StepEdge.tsx @@ -21,7 +21,34 @@ function createStepEdge(params: { isInternal: boolean }) { }); } +/** + * Component that can be used inside a custom edge to render a step edge. + * + * @public + * @example + * + * ```tsx + * import { StepEdge } from '@xyflow/react'; + * + * function CustomEdge({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }) { + * return ( + * + * ); + * } + * ``` + */ const StepEdge = createStepEdge({ isInternal: false }); + +/** + * @internal + */ const StepEdgeInternal = createStepEdge({ isInternal: true }); StepEdge.displayName = 'StepEdge'; diff --git a/packages/react/src/components/Edges/StraightEdge.tsx b/packages/react/src/components/Edges/StraightEdge.tsx index 53d1ac29..4f4cd76b 100644 --- a/packages/react/src/components/Edges/StraightEdge.tsx +++ b/packages/react/src/components/Edges/StraightEdge.tsx @@ -50,7 +50,32 @@ function createStraightEdge(params: { isInternal: boolean }) { ); } +/** + * Component that can be used inside a custom edge to render a straight line. + * + * @public + * @example + * + * ```tsx + * import { StraightEdge } from '@xyflow/react'; + * + * function CustomEdge({ sourceX, sourceY, targetX, targetY }) { + * return ( + * + * ); + * } + * ``` + */ const StraightEdge = createStraightEdge({ isInternal: false }); + +/** + * @internal + */ const StraightEdgeInternal = createStraightEdge({ isInternal: true }); StraightEdge.displayName = 'StraightEdge'; From c5a8c23773e5985be6b37abacdac743911be8c09 Mon Sep 17 00:00:00 2001 From: moklick Date: Sat, 22 Mar 2025 15:38:08 +0100 Subject: [PATCH 066/157] chore(changeset): add --- .changeset/polite-drinks-listen.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/polite-drinks-listen.md diff --git a/.changeset/polite-drinks-listen.md b/.changeset/polite-drinks-listen.md new file mode 100644 index 00000000..34be961a --- /dev/null +++ b/.changeset/polite-drinks-listen.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Add TSDoc annotations for exported edges From a6604eb2c6fd8608a4505160d4401da1ad7b01e9 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Mon, 24 Mar 2025 20:24:06 +0100 Subject: [PATCH 067/157] fix: improve TSDoc comments for `BackgroundProps` --- .../additional-components/Background/types.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/react/src/additional-components/Background/types.ts b/packages/react/src/additional-components/Background/types.ts index 50219e2d..d805a91c 100644 --- a/packages/react/src/additional-components/Background/types.ts +++ b/packages/react/src/additional-components/Background/types.ts @@ -16,6 +16,7 @@ export enum BackgroundVariant { * @expand */ export type BackgroundProps = { + /** When multiple backgrounds are present on the page, each one should have a unique id. */ id?: string; /** Color of the pattern */ color?: string; @@ -25,16 +26,31 @@ export type BackgroundProps = { className?: string; /** Class applied to the pattern */ patternClassName?: string; - /** Gap between repetitions of the pattern */ + /** + * The gap between patterns. Passing in a tuple allows you to control the x and y gap + * independently. + * @default '28' + */ gap?: number | [number, number]; - /** Size of a single pattern element */ + /** + * The radius of each dot or the size of each rectangle if `BackgroundVariant.Dots` or + * `BackgroundVariant.Cross` is used. This defaults to 1 or 6 respectively, or ignored if + * `BackgroundVariant.Lines` is used. + */ size?: number; - /** Offset of the pattern */ + /** + * Offset of the pattern + * @default 2 + */ offset?: number | [number, number]; - /** Line width of the Line pattern */ + /** + * The stroke thickness used when drawing the pattern. + * @default 1 + */ lineWidth?: number; /** * Variant of the pattern + * @default BackgroundVariant.Dots * @example BackgroundVariant.Lines, BackgroundVariant.Dots, BackgroundVariant.Cross * 'lines', 'dots', 'cross' */ From 0cdda42cdd1cd43d43d43c44e54b7b9f7a716ca9 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Mon, 24 Mar 2025 20:25:24 +0100 Subject: [PATCH 068/157] Create empty-swans-exercise.md --- .changeset/empty-swans-exercise.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-swans-exercise.md diff --git a/.changeset/empty-swans-exercise.md b/.changeset/empty-swans-exercise.md new file mode 100644 index 00000000..8769d594 --- /dev/null +++ b/.changeset/empty-swans-exercise.md @@ -0,0 +1,5 @@ +--- +"@xyflow/react": patch +--- + +fix: improve TSDoc comments for `BackgroundProps` From d76aefd8b04fda6b9e2219399dfdd347b269fb2a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Mon, 24 Mar 2025 22:42:21 +0100 Subject: [PATCH 069/157] upd --- packages/react/src/types/edges.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 4d1e3f04..3b922796 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -23,7 +23,11 @@ import { EdgeTypes, InternalNode, Node } from '.'; * @inline */ export type EdgeLabelOptions = { - label?: string | ReactNode; + /** + * The label or custom element to render along the edge. This is commonly a text label or some + * custom controls. + */ + label?: ReactNode; labelStyle?: CSSProperties; labelShowBg?: boolean; labelBgStyle?: CSSProperties; @@ -136,13 +140,20 @@ export type EdgeProps = Pick< */ export type BaseEdgeProps = Omit, 'd'> & EdgeLabelOptions & { - /** Additional padding where interacting with an edge is still possible */ + /** + * The width of the invisible area around the edge that the user can interact with. This is + * useful for making the edge easier to click or hover over. + */ interactionWidth?: number; /** The x position of edge label */ labelX?: number; /** The y position of edge label */ labelY?: number; - /** SVG path of the edge */ + /** + * The SVG path string that defines the edge. This should look something like + * `'M 0 0 L 100 100'` for a simple line. The utility functions like `getSimpleBezierEdge` can + * be used to generate this string for you. + */ path: string; }; From 7eb6eb0709e451d7628bfdbc3ced89b3bb57b626 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Mon, 24 Mar 2025 22:43:32 +0100 Subject: [PATCH 070/157] Create forty-phones-lick.md --- .changeset/forty-phones-lick.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/forty-phones-lick.md diff --git a/.changeset/forty-phones-lick.md b/.changeset/forty-phones-lick.md new file mode 100644 index 00000000..86132fa3 --- /dev/null +++ b/.changeset/forty-phones-lick.md @@ -0,0 +1,5 @@ +--- +"@xyflow/react": patch +--- + +fix: improve TSDoc comments for `EdgeLabelOptions` and `BaseEdgeProps` From 1202c9a68772776a9259c11b8f2ae404b6f16acf Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 25 Mar 2025 13:10:13 +0100 Subject: [PATCH 071/157] paddings with units --- packages/system/src/types/general.ts | 18 ++++++- packages/system/src/utils/general.ts | 80 +++++++++++++++++++++++++--- packages/system/src/utils/graph.ts | 3 +- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 1f6b2ecf..9acb3316 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -91,12 +91,26 @@ export type FitViewParamsBase = { maxZoom: number; }; +export type PaddingUnit = 'px' | '%'; +export type PaddingWithUnit = `${number}${PaddingUnit}` | number; + +export type Padding = + | PaddingWithUnit + | [padding: PaddingWithUnit] + | [paddingY: PaddingWithUnit, paddingX: PaddingWithUnit] + | [paddingTop: PaddingWithUnit, paddingX: PaddingWithUnit, paddingBottom: PaddingWithUnit] + | [ + paddingTop: PaddingWithUnit, + paddingRight: PaddingWithUnit, + paddingBottom: PaddingWithUnit, + paddingLeft: PaddingWithUnit + ]; + /** * @inline */ export type FitViewOptionsBase = { - padding?: number | [number, number]; - paddingUnit?: 'px' | '%'; + padding?: Padding; includeHiddenNodes?: boolean; minZoom?: number; maxZoom?: number; diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 90ff64fa..a21908bb 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -10,6 +10,8 @@ import type { Transform, InternalNodeBase, NodeLookup, + Padding, + PaddingWithUnit, } from '../types'; import { type Viewport } from '../types'; import { getNodePositionWithOrigin, isInternalNodeBase } from './graph'; @@ -173,6 +175,71 @@ export const rendererPointToPoint = ({ x, y }: XYPosition, [tx, ty, tScale]: Tra }; }; +function parsePadding(padding: PaddingWithUnit, viewportDimension: number, bound: number): number { + if (typeof padding === 'number') { + return bound * padding; + } + + if (typeof padding === 'string' && padding.endsWith('px')) { + return parseFloat(padding.slice(0, -2)); + } + + if (typeof padding === 'string' && padding.endsWith('%')) { + return viewportDimension * parseFloat(padding.slice(0, -1)); + } + + return 0; +} + +function parsePaddings( + padding: Padding, + viewportDiemsions: Dimensions, + bounds: Dimensions +): [number, number, number, number] { + if (typeof padding === 'number') { + return [padding, padding, padding, padding]; + } + + if (typeof padding === 'string') { + const paddingX = parsePadding(padding, viewportDiemsions.width, bounds.width); + const paddingY = parsePadding(padding, viewportDiemsions.height, bounds.height); + return [paddingY, paddingX, paddingY, paddingX]; + } + + if (Array.isArray(padding)) { + switch (padding.length) { + case 1: { + const paddingX = parsePadding(padding[0], viewportDiemsions.width, bounds.width); + const paddingY = parsePadding(padding[0], viewportDiemsions.height, bounds.height); + return [paddingY, paddingX, paddingY, paddingX]; + } + case 2: { + const [pY, pX] = padding; + const paddingY = parsePadding(pY, viewportDiemsions.height, bounds.height); + const paddingX = parsePadding(pX, viewportDiemsions.width, bounds.width); + return [paddingY, paddingX, paddingY, paddingX]; + } + case 3: { + const [pTop, pX, pBottom] = padding; + const paddingTop = parsePadding(pTop, viewportDiemsions.height, bounds.height); + const padddingX = parsePadding(pX, viewportDiemsions.width, bounds.width); + const paddingBottom = parsePadding(pBottom, viewportDiemsions.height, bounds.height); + return [paddingTop, padddingX, paddingBottom, padddingX]; + } + case 4: { + const [pTop, pRight, pBottom, pLeft] = padding; + const paddingTop = parsePadding(pTop, viewportDiemsions.height, bounds.height); + const paddingRight = parsePadding(pRight, viewportDiemsions.width, bounds.width); + const paddingBottom = parsePadding(pBottom, viewportDiemsions.height, bounds.height); + const paddingLeft = parsePadding(pLeft, viewportDiemsions.width, bounds.width); + return [paddingTop, paddingRight, paddingBottom, paddingLeft]; + } + } + } + + return [0, 0, 0, 0]; +} + /** * Returns a viewport that encloses the given bounds with optional padding. * @public @@ -195,15 +262,16 @@ export const getViewportForBounds = ( height: number, minZoom: number, maxZoom: number, - padding: number | [number, number], - paddingUnit: 'px' | '%' + padding: Padding = 0 ): Viewport => { - const [paddingX, paddingY] = Array.isArray(padding) ? [padding[0], padding[1]] : [padding, padding]; + // const [paddingX, paddingY] = Array.isArray(padding) ? [padding[0], padding[1]] : [padding, padding]; - const isPixelPadding = paddingUnit === 'px'; + // const isPixelPadding = paddingUnit === 'px'; - const xZoom = width / (isPixelPadding ? bounds.width + paddingX : bounds.width * (1 + paddingX)); - const yZoom = height / (isPixelPadding ? bounds.height + paddingY : bounds.height * (1 + paddingY)); + const [paddingTop, paddingRight, paddingBottom, paddingLeft] = parsePaddings(padding, { width, height }, bounds); + + const xZoom = (width - paddingLeft - paddingRight) / bounds.width; + const yZoom = (height - paddingTop - paddingBottom) / bounds.height; const zoom = Math.min(xZoom, yZoom); const clampedZoom = clamp(zoom, minZoom, maxZoom); diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 930c4adb..e14f81cd 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -372,8 +372,7 @@ export async function fitViewport< height, options?.minZoom ?? minZoom, options?.maxZoom ?? maxZoom, - options?.padding ?? 0.1, - options?.paddingUnit ?? '%' + options?.padding ?? 0.1 ); await panZoom.setViewport(viewport, { duration: options?.duration }); From bb1a97d7a8cb7375c18c48567fa544520f5e5bd7 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 25 Mar 2025 13:43:30 +0100 Subject: [PATCH 072/157] fix uncontrolled flows --- packages/react/src/store/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 8b219d27..e099ca95 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -64,7 +64,6 @@ const createStore = ({ fitViewResolver?.resolve(value); set({ fitViewResolver: null }); }); - set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); } return { @@ -89,6 +88,7 @@ const createStore = ({ if (fitViewQueued && nodesInitialized) { resolveFitView(); + set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); } else { set({ nodes }); } @@ -138,6 +138,7 @@ const createStore = ({ if (fitViewQueued) { resolveFitView(); + set({ fitViewQueued: false, fitViewOptions: undefined }); } else { // we always want to trigger useStore calls whenever updateNodeInternals is called set({}); From 137b23c6a7bb01cc76f09b3ecb74b928d15998cc Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 25 Mar 2025 17:13:21 +0100 Subject: [PATCH 073/157] add initial support for asymmetric paddings --- examples/react/src/examples/Basic/index.tsx | 3 + packages/system/src/utils/general.ts | 78 +++++++++++---------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/examples/react/src/examples/Basic/index.tsx b/examples/react/src/examples/Basic/index.tsx index bb53b309..e399ab88 100644 --- a/examples/react/src/examples/Basic/index.tsx +++ b/examples/react/src/examples/Basic/index.tsx @@ -146,6 +146,9 @@ const BasicFlow = () => { minZoom={0.2} maxZoom={4} fitView + fitViewOptions={{ + padding: ['30%', '10%', '10%', '20%'], + }} defaultEdgeOptions={defaultEdgeOptions} selectNodesOnDrag={false} elevateEdgesOnSelect diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index a21908bb..0d47025b 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -175,63 +175,68 @@ export const rendererPointToPoint = ({ x, y }: XYPosition, [tx, ty, tScale]: Tra }; }; -function parsePadding(padding: PaddingWithUnit, viewportDimension: number, bound: number): number { +function paddingError(padding: PaddingWithUnit) { + console.error( + `[React Flow] The padding value "${padding}" is invalid. Please provide a number or a string with a valid unit (px or %).` + ); +} + +function parsePadding(padding: PaddingWithUnit, viewport: number): number { if (typeof padding === 'number') { - return bound * padding; + return viewport - viewport / (1 + padding * 0.5); } if (typeof padding === 'string' && padding.endsWith('px')) { - return parseFloat(padding.slice(0, -2)); + const paddingValue = parseFloat(padding); + if (!Number.isNaN(paddingValue)) { + return paddingValue; + } } if (typeof padding === 'string' && padding.endsWith('%')) { - return viewportDimension * parseFloat(padding.slice(0, -1)); + const paddingValue = parseFloat(padding); + if (!Number.isNaN(paddingValue)) { + return viewport * paddingValue * 0.01; + } } + paddingError(padding); return 0; } -function parsePaddings( - padding: Padding, - viewportDiemsions: Dimensions, - bounds: Dimensions -): [number, number, number, number] { - if (typeof padding === 'number') { - return [padding, padding, padding, padding]; - } - - if (typeof padding === 'string') { - const paddingX = parsePadding(padding, viewportDiemsions.width, bounds.width); - const paddingY = parsePadding(padding, viewportDiemsions.height, bounds.height); +function parsePaddings(padding: Padding, width: number, height: number): [number, number, number, number] { + if (typeof padding === 'string' || typeof padding === 'number') { + const paddingY = parsePadding(padding, height); + const paddingX = parsePadding(padding, width); return [paddingY, paddingX, paddingY, paddingX]; } if (Array.isArray(padding)) { switch (padding.length) { case 1: { - const paddingX = parsePadding(padding[0], viewportDiemsions.width, bounds.width); - const paddingY = parsePadding(padding[0], viewportDiemsions.height, bounds.height); + const paddingY = parsePadding(padding[0], height); + const paddingX = parsePadding(padding[0], width); return [paddingY, paddingX, paddingY, paddingX]; } case 2: { const [pY, pX] = padding; - const paddingY = parsePadding(pY, viewportDiemsions.height, bounds.height); - const paddingX = parsePadding(pX, viewportDiemsions.width, bounds.width); + const paddingY = parsePadding(pY, height); + const paddingX = parsePadding(pX, width); return [paddingY, paddingX, paddingY, paddingX]; } case 3: { const [pTop, pX, pBottom] = padding; - const paddingTop = parsePadding(pTop, viewportDiemsions.height, bounds.height); - const padddingX = parsePadding(pX, viewportDiemsions.width, bounds.width); - const paddingBottom = parsePadding(pBottom, viewportDiemsions.height, bounds.height); + const paddingTop = parsePadding(pTop, height); + const padddingX = parsePadding(pX, width); + const paddingBottom = parsePadding(pBottom, height); return [paddingTop, padddingX, paddingBottom, padddingX]; } case 4: { const [pTop, pRight, pBottom, pLeft] = padding; - const paddingTop = parsePadding(pTop, viewportDiemsions.height, bounds.height); - const paddingRight = parsePadding(pRight, viewportDiemsions.width, bounds.width); - const paddingBottom = parsePadding(pBottom, viewportDiemsions.height, bounds.height); - const paddingLeft = parsePadding(pLeft, viewportDiemsions.width, bounds.width); + const paddingTop = parsePadding(pTop, height); + const paddingRight = parsePadding(pRight, width); + const paddingBottom = parsePadding(pBottom, height); + const paddingLeft = parsePadding(pLeft, width); return [paddingTop, paddingRight, paddingBottom, paddingLeft]; } } @@ -262,23 +267,24 @@ export const getViewportForBounds = ( height: number, minZoom: number, maxZoom: number, - padding: Padding = 0 + padding: Padding ): Viewport => { - // const [paddingX, paddingY] = Array.isArray(padding) ? [padding[0], padding[1]] : [padding, padding]; + const [paddingTop, paddingRight, paddingBottom, paddingLeft] = parsePaddings(padding, width, height); + const paddingX = paddingLeft + paddingRight; + const paddingY = paddingTop + paddingBottom; - // const isPixelPadding = paddingUnit === 'px'; + console.log({ paddingTop, paddingRight, paddingBottom, paddingLeft }); + console.log(paddingX / paddingLeft); - const [paddingTop, paddingRight, paddingBottom, paddingLeft] = parsePaddings(padding, { width, height }, bounds); - - const xZoom = (width - paddingLeft - paddingRight) / bounds.width; - const yZoom = (height - paddingTop - paddingBottom) / bounds.height; + const xZoom = (width - paddingX) / bounds.width; + const yZoom = (height - paddingY) / bounds.height; const zoom = Math.min(xZoom, yZoom); const clampedZoom = clamp(zoom, minZoom, maxZoom); const boundsCenterX = bounds.x + bounds.width / 2; const boundsCenterY = bounds.y + bounds.height / 2; - const x = width / 2 - boundsCenterX * clampedZoom; - const y = height / 2 - boundsCenterY * clampedZoom; + const x = width / 2 - boundsCenterX * clampedZoom - paddingX * 0.5 + paddingLeft; + const y = height / 2 - boundsCenterY * clampedZoom - paddingY * 0.5 + paddingTop; return { x, y, zoom: clampedZoom }; }; From e3ecf999aad558b2bc493648f6049da7a1fc87d2 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 25 Mar 2025 18:05:58 +0100 Subject: [PATCH 074/157] correctly apply asymetric paddings --- examples/react/src/examples/Basic/index.tsx | 3 +- packages/system/src/utils/general.ts | 35 +++++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/examples/react/src/examples/Basic/index.tsx b/examples/react/src/examples/Basic/index.tsx index e399ab88..6b538593 100644 --- a/examples/react/src/examples/Basic/index.tsx +++ b/examples/react/src/examples/Basic/index.tsx @@ -147,7 +147,8 @@ const BasicFlow = () => { maxZoom={4} fitView fitViewOptions={{ - padding: ['30%', '10%', '10%', '20%'], + // top, right, bottom, left + padding: ['100px', '0%', '0%', '50px'], }} defaultEdgeOptions={defaultEdgeOptions} selectNodesOnDrag={false} diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 0d47025b..f6b796a7 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -273,9 +273,6 @@ export const getViewportForBounds = ( const paddingX = paddingLeft + paddingRight; const paddingY = paddingTop + paddingBottom; - console.log({ paddingTop, paddingRight, paddingBottom, paddingLeft }); - console.log(paddingX / paddingLeft); - const xZoom = (width - paddingX) / bounds.width; const yZoom = (height - paddingY) / bounds.height; @@ -283,12 +280,38 @@ export const getViewportForBounds = ( const clampedZoom = clamp(zoom, minZoom, maxZoom); const boundsCenterX = bounds.x + bounds.width / 2; const boundsCenterY = bounds.y + bounds.height / 2; - const x = width / 2 - boundsCenterX * clampedZoom - paddingX * 0.5 + paddingLeft; - const y = height / 2 - boundsCenterY * clampedZoom - paddingY * 0.5 + paddingTop; + const x = width / 2 - boundsCenterX * clampedZoom; + const y = height / 2 - boundsCenterY * clampedZoom; - return { x, y, zoom: clampedZoom }; + const realPadding = calculatePadding(bounds, x, y, clampedZoom, width, height); + + const paddingDifferences = { + left: Math.min(Math.floor(realPadding.left) - Math.floor(paddingLeft), 0), + top: Math.min(Math.floor(realPadding.top) - Math.floor(paddingTop), 0), + right: Math.min(Math.floor(realPadding.right) - Math.floor(paddingRight), 0), + bottom: Math.min(Math.floor(realPadding.bottom) - Math.floor(paddingBottom), 0), + }; + return { + x: x - paddingDifferences.left + paddingDifferences.right, + y: y - paddingDifferences.top + paddingDifferences.bottom, + zoom: clampedZoom, + }; }; +function calculatePadding(bounds: Rect, x: number, y: number, zoom: number, width: number, height: number) { + const { x: paddingLeft, y: paddingTop } = rendererPointToPoint(bounds, [x, y, zoom]); + + const { x: boundRight, y: boundBottom } = rendererPointToPoint( + { x: bounds.x + bounds.width, y: bounds.y + bounds.height }, + [x, y, zoom] + ); + + const paddingRight = width - boundRight; + const paddingBottom = height - boundBottom; + + return { left: paddingLeft, top: paddingTop, right: paddingRight, bottom: paddingBottom }; +} + export const isMacOs = () => typeof navigator !== 'undefined' && navigator?.userAgent?.indexOf('Mac') >= 0; export function isCoordinateExtent(extent?: CoordinateExtent | 'parent'): extent is CoordinateExtent { From 9e2e3c22a9c460d7e4895f594c0211656e1ac3b3 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 18:58:01 +0100 Subject: [PATCH 075/157] fix: improve TSDoc comments for `ControlProps` --- .../additional-components/Controls/types.ts | 42 +++++++++++++++---- packages/system/src/types/general.ts | 7 ++-- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/packages/react/src/additional-components/Controls/types.ts b/packages/react/src/additional-components/Controls/types.ts index bccd1117..dad4813b 100644 --- a/packages/react/src/additional-components/Controls/types.ts +++ b/packages/react/src/additional-components/Controls/types.ts @@ -7,24 +7,42 @@ import type { FitViewOptions } from '../../types'; * @expand */ export type ControlProps = { - /** Show button for zoom in/out */ + /** + * Whether or not to show the zoom in and zoom out buttons. These buttons will adjust the viewport + * zoom by a fixed amount each press. + * @default true + */ showZoom?: boolean; - /** Show button for fit view */ + /** + * Whether or not to show the fit view button. By default, this button will adjust the viewport so + * that all nodes are visible at once. + * @default true + */ showFitView?: boolean; - /** Show button for toggling interactivity */ + /** + * Show button for toggling interactivity + * @default true + */ showInteractive?: boolean; - /** Options being used when fit view button is clicked */ + /** + * Customise the options for the fit view button. These are the same options you would pass to the + * fitView function. + */ fitViewOptions?: FitViewOptions; - /** Callback when zoom in button is clicked */ + /** Called in addition the default zoom behavior when the zoom in button is clicked. */ onZoomIn?: () => void; - /** Callback when zoom out button is clicked */ + /** Called in addition the default zoom behavior when the zoom out button is clicked. */ onZoomOut?: () => void; - /** Callback when fit view button is clicked */ + /** + * Called when the fit view button is clicked. When this is not provided, the viewport will be + * adjusted so that all nodes are visible. + */ onFitView?: () => void; - /** Callback when interactivity is toggled */ + /** Called when the interactive (lock) button is clicked. */ onInteractiveChange?: (interactiveStatus: boolean) => void; /** * Position of the controls on the pane + * @default PanelPosition.BottomLeft * @example PanelPosition.TopLeft, PanelPosition.TopRight, * PanelPosition.BottomLeft, PanelPosition.BottomRight */ @@ -32,9 +50,15 @@ export type ControlProps = { children?: ReactNode; /** Style applied to container */ style?: React.CSSProperties; - /** ClassName applied to container */ + /** Class name applied to container */ className?: string; + /** + * @default 'React Flow controls' + */ 'aria-label'?: string; + /** + * @default 'vertical' + */ orientation?: 'horizontal' | 'vertical'; }; diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index fc92bc7e..418902da 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -2,8 +2,7 @@ import type { Selection as D3Selection } from 'd3-selection'; import type { D3DragEvent, SubjectPosition } from 'd3-drag'; import type { ZoomBehavior } from 'd3-zoom'; -// this is needed for the Selection type to include the transition function :/ -// eslint-disable-next-line @typescript-eslint/no-unused-vars +// eslint-disable-next-line @typescript-eslint/no-unused-vars -- this is needed for the Selection type to include the transition function :/ import type { Transition } from 'd3-transition'; import type { XYPosition, Rect, Position } from './utils'; @@ -41,14 +40,14 @@ export type Connection = { }; /** - * The `HandleConnection` type is an extention of a basic [Connection](/api-reference/types/connection) that includes the `edgeId`. + * The `HandleConnection` type is an extension of a basic [Connection](/api-reference/types/connection) that includes the `edgeId`. */ export type HandleConnection = Connection & { edgeId: string; }; /** - * The `NodeConnection` type is an extention of a basic [Connection](/api-reference/types/connection) that includes the `edgeId`. + * The `NodeConnection` type is an extension of a basic [Connection](/api-reference/types/connection) that includes the `edgeId`. * */ export type NodeConnection = Connection & { From bce8542df19c33f3cd9225f483435e8a7aa4ed94 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 18:59:06 +0100 Subject: [PATCH 076/157] Create fuzzy-cameras-nail.md --- .changeset/fuzzy-cameras-nail.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fuzzy-cameras-nail.md diff --git a/.changeset/fuzzy-cameras-nail.md b/.changeset/fuzzy-cameras-nail.md new file mode 100644 index 00000000..d2124f5d --- /dev/null +++ b/.changeset/fuzzy-cameras-nail.md @@ -0,0 +1,5 @@ +--- +"@xyflow/react": patch +--- + +fix: improve TSDoc comments for `ControlProps` From 4a45770cc753551ce839e447a4eb97c439ecc5d2 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 19:21:06 +0100 Subject: [PATCH 077/157] feat: export `EdgeLabelRendererProps` --- packages/react/src/components/EdgeLabelRenderer/index.tsx | 6 +++++- packages/react/src/index.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/EdgeLabelRenderer/index.tsx b/packages/react/src/components/EdgeLabelRenderer/index.tsx index 2b603dc3..7115b495 100644 --- a/packages/react/src/components/EdgeLabelRenderer/index.tsx +++ b/packages/react/src/components/EdgeLabelRenderer/index.tsx @@ -6,6 +6,10 @@ import type { ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__edgelabel-renderer'); +export type EdgeLabelRendererProps = { + children: ReactNode +} + /** * Edges are SVG-based. If you want to render more complex labels you can use the * `` component to access a div based renderer. This component @@ -47,7 +51,7 @@ const selector = (s: ReactFlowState) => s.domNode?.querySelector('.react-flow__e * add mouse interactions you need to set the style `pointerEvents: all` and add * the `nopan` class on the label or the element you want to interact with. */ -export function EdgeLabelRenderer({ children }: { children: ReactNode }) { +export function EdgeLabelRenderer({ children }: EdgeLabelRendererProps) { const edgeLabelRenderer = useStore(selector); if (!edgeLabelRenderer) { diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index a6e3d6d2..1cb3764c 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -9,7 +9,7 @@ export { SmoothStepEdge } from './components/Edges/SmoothStepEdge'; export { BaseEdge } from './components/Edges/BaseEdge'; export { ReactFlowProvider } from './components/ReactFlowProvider'; export { Panel, type PanelProps } from './components/Panel'; -export { EdgeLabelRenderer } from './components/EdgeLabelRenderer'; +export { EdgeLabelRenderer, type EdgeLabelRendererProps } from './components/EdgeLabelRenderer'; export { ViewportPortal } from './components/ViewportPortal'; export { useReactFlow } from './hooks/useReactFlow'; From c215455735385ef5e12e4130164b9d01f9c18aa2 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 19:35:08 +0100 Subject: [PATCH 078/157] a --- .changeset/tame-bulldogs-juggle.md | 5 +++++ packages/react/src/components/Edges/EdgeText.tsx | 6 +++--- packages/react/src/types/edges.ts | 9 +++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 .changeset/tame-bulldogs-juggle.md diff --git a/.changeset/tame-bulldogs-juggle.md b/.changeset/tame-bulldogs-juggle.md new file mode 100644 index 00000000..1f915341 --- /dev/null +++ b/.changeset/tame-bulldogs-juggle.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `EdgeLabelOptions` and `EdgeTextProps` diff --git a/packages/react/src/components/Edges/EdgeText.tsx b/packages/react/src/components/Edges/EdgeText.tsx index 9807302a..6646f683 100644 --- a/packages/react/src/components/Edges/EdgeText.tsx +++ b/packages/react/src/components/Edges/EdgeText.tsx @@ -8,9 +8,9 @@ function EdgeTextComponent({ x, y, label, - labelStyle = {}, + labelStyle, labelShowBg = true, - labelBgStyle = {}, + labelBgStyle, labelBgPadding = [2, 4], labelBgBorderRadius = 2, children, @@ -34,7 +34,7 @@ function EdgeTextComponent({ } }, [label]); - if (typeof label === 'undefined' || !label) { + if (!label) { return null; } diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 3b922796..8fddf865 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -28,6 +28,9 @@ export type EdgeLabelOptions = { * custom controls. */ label?: ReactNode; + /** + * Custom styles to apply to the label. + */ labelStyle?: CSSProperties; labelShowBg?: boolean; labelBgStyle?: CSSProperties; @@ -108,7 +111,13 @@ export type DefaultEdgeOptions = DefaultEdgeOptionsBase; export type EdgeTextProps = SVGAttributes & EdgeLabelOptions & { + /** + * The x position where the label should be rendered. + */ x: number; + /** + * The y position where the label should be rendered. + */ y: number; }; From ba2bfbb49aafac979f94b0136bb408faea12d5c6 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 19:37:37 +0100 Subject: [PATCH 079/157] add changeset --- .changeset/large-suns-notice.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/large-suns-notice.md diff --git a/.changeset/large-suns-notice.md b/.changeset/large-suns-notice.md new file mode 100644 index 00000000..edef2e3a --- /dev/null +++ b/.changeset/large-suns-notice.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +feat: export `EdgeLabelRendererProps` From 589421542386906ec49d8469cac551b8f7ea1c47 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 25 Mar 2025 22:28:17 +0100 Subject: [PATCH 080/157] add changeset --- .changeset/healthy-baboons-judge.md | 5 +++++ .../src/additional-components/NodeToolbar/types.ts | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .changeset/healthy-baboons-judge.md diff --git a/.changeset/healthy-baboons-judge.md b/.changeset/healthy-baboons-judge.md new file mode 100644 index 00000000..b31a6857 --- /dev/null +++ b/.changeset/healthy-baboons-judge.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `NodeToolbarProps` diff --git a/packages/react/src/additional-components/NodeToolbar/types.ts b/packages/react/src/additional-components/NodeToolbar/types.ts index 91a717da..96756983 100644 --- a/packages/react/src/additional-components/NodeToolbar/types.ts +++ b/packages/react/src/additional-components/NodeToolbar/types.ts @@ -5,7 +5,10 @@ import type { Position, Align } from '@xyflow/system'; * @expand */ export type NodeToolbarProps = HTMLAttributes & { - /** Id of the node, or array of ids the toolbar should be displayed at */ + /** + * By passing in an array of node id's you can render a single tooltip for a group or collection + * of nodes. + */ nodeId?: string | string[]; /** If true, node toolbar is visible even if node is not selected */ isVisible?: boolean; @@ -15,7 +18,10 @@ export type NodeToolbarProps = HTMLAttributes & { * Position.BottomLeft, Position.BottomRight */ position?: Position; - /** Offset the toolbar from the node */ + /** + * The space between the node and the toolbar, measured in pixels. + * @default 10 + */ offset?: number; /** * Align the toolbar relative to the node From 11dfc46e84d58327f426aea9b2e09b4fa62f89a6 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 26 Mar 2025 09:26:36 +0100 Subject: [PATCH 081/157] chore(useKeyPress): prevent event swallowing for buttons #5037 --- packages/system/src/utils/dom.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/system/src/utils/dom.ts b/packages/system/src/utils/dom.ts index 2311153f..4195ea3a 100644 --- a/packages/system/src/utils/dom.ts +++ b/packages/system/src/utils/dom.ts @@ -35,7 +35,7 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({ export const getHostForElement = (element: HTMLElement | EventTarget | null): Document | ShadowRoot => ((element as Partial | null)?.getRootNode?.() as Document | ShadowRoot) || window?.document; -const inputTags = ['INPUT', 'SELECT', 'TEXTAREA']; +const inputTags = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON']; export function isInputDOMNode(event: KeyboardEvent): boolean { // using composed path for handling shadow dom From 5d15b01ba8cb349d6397a6ed8162848b4dfec293 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 26 Mar 2025 09:27:45 +0100 Subject: [PATCH 082/157] chore(changeset): add --- .changeset/great-pillows-drive.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/great-pillows-drive.md diff --git a/.changeset/great-pillows-drive.md b/.changeset/great-pillows-drive.md new file mode 100644 index 00000000..0b099cf8 --- /dev/null +++ b/.changeset/great-pillows-drive.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Do not swallow key events when a button is focused From 48d08379392816dcc00c312c5c534d21ef1ee38c Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 26 Mar 2025 12:49:43 +0100 Subject: [PATCH 083/157] use object instead of array for paddings & clean up fitView code --- examples/react/src/examples/Basic/index.tsx | 3 +- packages/system/src/types/general.ts | 17 +-- packages/system/src/utils/general.ts | 161 +++++++++++--------- 3 files changed, 99 insertions(+), 82 deletions(-) diff --git a/examples/react/src/examples/Basic/index.tsx b/examples/react/src/examples/Basic/index.tsx index 6b538593..5754fd62 100644 --- a/examples/react/src/examples/Basic/index.tsx +++ b/examples/react/src/examples/Basic/index.tsx @@ -147,8 +147,7 @@ const BasicFlow = () => { maxZoom={4} fitView fitViewOptions={{ - // top, right, bottom, left - padding: ['100px', '0%', '0%', '50px'], + padding: { top: '100px', left: '0%', right: '10%', bottom: 0.1 }, }} defaultEdgeOptions={defaultEdgeOptions} selectNodesOnDrag={false} diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 806b354e..2a34e9ff 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -96,15 +96,14 @@ export type PaddingWithUnit = `${number}${PaddingUnit}` | number; export type Padding = | PaddingWithUnit - | [padding: PaddingWithUnit] - | [paddingY: PaddingWithUnit, paddingX: PaddingWithUnit] - | [paddingTop: PaddingWithUnit, paddingX: PaddingWithUnit, paddingBottom: PaddingWithUnit] - | [ - paddingTop: PaddingWithUnit, - paddingRight: PaddingWithUnit, - paddingBottom: PaddingWithUnit, - paddingLeft: PaddingWithUnit - ]; + | { + top?: PaddingWithUnit; + right?: PaddingWithUnit; + bottom?: PaddingWithUnit; + left?: PaddingWithUnit; + x?: PaddingWithUnit; + y?: PaddingWithUnit; + }; /** * @inline diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index f6b796a7..5b4c6995 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -175,74 +175,103 @@ export const rendererPointToPoint = ({ x, y }: XYPosition, [tx, ty, tScale]: Tra }; }; -function paddingError(padding: PaddingWithUnit) { - console.error( - `[React Flow] The padding value "${padding}" is invalid. Please provide a number or a string with a valid unit (px or %).` - ); -} - +/** + * Parses a single padding value to a number + * @internal + * @param padding - Padding to parse + * @param viewport - Width or height of the viewport + * @returns The padding in pixels + */ function parsePadding(padding: PaddingWithUnit, viewport: number): number { if (typeof padding === 'number') { - return viewport - viewport / (1 + padding * 0.5); + return Math.floor(viewport - viewport / (1 + padding)); } if (typeof padding === 'string' && padding.endsWith('px')) { const paddingValue = parseFloat(padding); if (!Number.isNaN(paddingValue)) { - return paddingValue; + return Math.floor(paddingValue); } } if (typeof padding === 'string' && padding.endsWith('%')) { const paddingValue = parseFloat(padding); if (!Number.isNaN(paddingValue)) { - return viewport * paddingValue * 0.01; + return Math.floor(viewport * paddingValue * 0.01); } } - paddingError(padding); + console.error( + `[React Flow] The padding value "${padding}" is invalid. Please provide a number or a string with a valid unit (px or %).` + ); return 0; } -function parsePaddings(padding: Padding, width: number, height: number): [number, number, number, number] { +/** + * Parses the paddings to an object with top, right, bottom, left, x and y paddings + * @internal + * @param padding - Padding to parse + * @param width - Width of the viewport + * @param height - Height of the viewport + * @returns An object with the paddings in pixels + */ +function parsePaddings( + padding: Padding, + width: number, + height: number +): { top: number; bottom: number; left: number; right: number; x: number; y: number } { if (typeof padding === 'string' || typeof padding === 'number') { const paddingY = parsePadding(padding, height); const paddingX = parsePadding(padding, width); - return [paddingY, paddingX, paddingY, paddingX]; + return { + top: paddingY, + right: paddingX, + bottom: paddingY, + left: paddingX, + x: paddingX * 2, + y: paddingY * 2, + }; } - if (Array.isArray(padding)) { - switch (padding.length) { - case 1: { - const paddingY = parsePadding(padding[0], height); - const paddingX = parsePadding(padding[0], width); - return [paddingY, paddingX, paddingY, paddingX]; - } - case 2: { - const [pY, pX] = padding; - const paddingY = parsePadding(pY, height); - const paddingX = parsePadding(pX, width); - return [paddingY, paddingX, paddingY, paddingX]; - } - case 3: { - const [pTop, pX, pBottom] = padding; - const paddingTop = parsePadding(pTop, height); - const padddingX = parsePadding(pX, width); - const paddingBottom = parsePadding(pBottom, height); - return [paddingTop, padddingX, paddingBottom, padddingX]; - } - case 4: { - const [pTop, pRight, pBottom, pLeft] = padding; - const paddingTop = parsePadding(pTop, height); - const paddingRight = parsePadding(pRight, width); - const paddingBottom = parsePadding(pBottom, height); - const paddingLeft = parsePadding(pLeft, width); - return [paddingTop, paddingRight, paddingBottom, paddingLeft]; - } - } + if (typeof padding === 'object') { + const top = parsePadding(padding.top ?? padding.y ?? 0, height); + const bottom = parsePadding(padding.bottom ?? padding.y ?? 0, height); + const left = parsePadding(padding.left ?? padding.x ?? 0, width); + const right = parsePadding(padding.right ?? padding.x ?? 0, width); + return { top, right, bottom, left, x: left + right, y: top + bottom }; } - return [0, 0, 0, 0]; + return { top: 0, right: 0, bottom: 0, left: 0, x: 0, y: 0 }; +} + +/** + * Calculates the resulting paddings if the new viewport is applied + * @internal + * @param bounds - Bounds to fit inside viewport + * @param x - X position of the viewport + * @param y - Y position of the viewport + * @param zoom - Zoom level of the viewport + * @param width - Width of the viewport + * @param height - Height of the viewport + * @returns An object with the minimum padding required to fit the bounds inside the viewport + */ +function calculateAppliedPaddings(bounds: Rect, x: number, y: number, zoom: number, width: number, height: number) { + const { x: left, y: top } = rendererPointToPoint(bounds, [x, y, zoom]); + + const { x: boundRight, y: boundBottom } = rendererPointToPoint( + { x: bounds.x + bounds.width, y: bounds.y + bounds.height }, + [x, y, zoom] + ); + + const right = width - boundRight; + const bottom = height - boundBottom; + + return { + left: Math.floor(left), + top: Math.floor(top), + right: Math.floor(right), + bottom: Math.floor(bottom), + }; } /** @@ -258,8 +287,8 @@ function parsePaddings(padding: Padding, width: number, height: number): [number * @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport} * @example * const { x, y, zoom } = getViewportForBounds( - *{ x: 0, y: 0, width: 100, height: 100}, - *1200, 800, 0.5, 2); + * { x: 0, y: 0, width: 100, height: 100}, + * 1200, 800, 0.5, 2); */ export const getViewportForBounds = ( bounds: Rect, @@ -269,49 +298,39 @@ export const getViewportForBounds = ( maxZoom: number, padding: Padding ): Viewport => { - const [paddingTop, paddingRight, paddingBottom, paddingLeft] = parsePaddings(padding, width, height); - const paddingX = paddingLeft + paddingRight; - const paddingY = paddingTop + paddingBottom; + // First we resolve all the paddings to actual pixel values + const p = parsePaddings(padding, width, height); - const xZoom = (width - paddingX) / bounds.width; - const yZoom = (height - paddingY) / bounds.height; + const xZoom = (width - p.x) / bounds.width; + const yZoom = (height - p.y) / bounds.height; + // We calculate the new x, y, zoom for a centered view const zoom = Math.min(xZoom, yZoom); const clampedZoom = clamp(zoom, minZoom, maxZoom); + const boundsCenterX = bounds.x + bounds.width / 2; const boundsCenterY = bounds.y + bounds.height / 2; const x = width / 2 - boundsCenterX * clampedZoom; const y = height / 2 - boundsCenterY * clampedZoom; - const realPadding = calculatePadding(bounds, x, y, clampedZoom, width, height); + // Then we calculate the minimum padding, to respect asymmetric paddings + const newPadding = calculateAppliedPaddings(bounds, x, y, clampedZoom, width, height); - const paddingDifferences = { - left: Math.min(Math.floor(realPadding.left) - Math.floor(paddingLeft), 0), - top: Math.min(Math.floor(realPadding.top) - Math.floor(paddingTop), 0), - right: Math.min(Math.floor(realPadding.right) - Math.floor(paddingRight), 0), - bottom: Math.min(Math.floor(realPadding.bottom) - Math.floor(paddingBottom), 0), + // We only want to have an offset if the newPadding is smaller than the required padding + const offset = { + left: Math.min(newPadding.left - p.left, 0), + top: Math.min(newPadding.top - p.top, 0), + right: Math.min(newPadding.right - p.right, 0), + bottom: Math.min(newPadding.bottom - p.bottom, 0), }; + return { - x: x - paddingDifferences.left + paddingDifferences.right, - y: y - paddingDifferences.top + paddingDifferences.bottom, + x: x - offset.left + offset.right, + y: y - offset.top + offset.bottom, zoom: clampedZoom, }; }; -function calculatePadding(bounds: Rect, x: number, y: number, zoom: number, width: number, height: number) { - const { x: paddingLeft, y: paddingTop } = rendererPointToPoint(bounds, [x, y, zoom]); - - const { x: boundRight, y: boundBottom } = rendererPointToPoint( - { x: bounds.x + bounds.width, y: bounds.y + bounds.height }, - [x, y, zoom] - ); - - const paddingRight = width - boundRight; - const paddingBottom = height - boundBottom; - - return { left: paddingLeft, top: paddingTop, right: paddingRight, bottom: paddingBottom }; -} - export const isMacOs = () => typeof navigator !== 'undefined' && navigator?.userAgent?.indexOf('Mac') >= 0; export function isCoordinateExtent(extent?: CoordinateExtent | 'parent'): extent is CoordinateExtent { From acba901d861aa84cb5beba60b24fff4cfde7ada6 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 26 Mar 2025 12:57:16 +0100 Subject: [PATCH 084/157] make two seperate changesets for fix and the new features --- .changeset/hungry-shrimps-remain.md | 5 +++++ .changeset/poor-poems-visit.md | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .changeset/hungry-shrimps-remain.md diff --git a/.changeset/hungry-shrimps-remain.md b/.changeset/hungry-shrimps-remain.md new file mode 100644 index 00000000..abf4ef75 --- /dev/null +++ b/.changeset/hungry-shrimps-remain.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': minor +--- + +You can now express paddings in fitViewOptions as pixels ('30px'), as viewport percentages ('20%') and define different paddings for each side. diff --git a/.changeset/poor-poems-visit.md b/.changeset/poor-poems-visit.md index 4aeb827d..8a258582 100644 --- a/.changeset/poor-poems-visit.md +++ b/.changeset/poor-poems-visit.md @@ -1,7 +1,7 @@ --- -'@xyflow/react': minor +'@xyflow/react': patch '@xyflow/svelte': patch '@xyflow/system': patch --- -Fix fitView not working when adding new nodes +Fix fitView not working immediately after adding new nodes From 85e212a5dc8e2ada03b97f2053b2bf40768557f2 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Wed, 26 Mar 2025 14:02:37 +0100 Subject: [PATCH 085/157] fix rounding error in pane test --- tests/playwright/e2e/pane.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/playwright/e2e/pane.spec.ts b/tests/playwright/e2e/pane.spec.ts index fade5e0c..802e0139 100644 --- a/tests/playwright/e2e/pane.spec.ts +++ b/tests/playwright/e2e/pane.spec.ts @@ -30,8 +30,8 @@ test.describe('Pane default', () => { const transformsAfter = await getTransform(viewport); - expect(transformsAfter.translateX - transformsBefore.translateX).toBe(100); - expect(transformsAfter.translateY - transformsBefore.translateY).toBe(100); + expect(Math.floor(transformsAfter.translateX - transformsBefore.translateX)).toBe(100); + expect(Math.floor(transformsAfter.translateY - transformsBefore.translateY)).toBe(100); }); test('scrolling the default pane zooms it', async ({ page }) => { From 238664e32229a6ff544770680b7103f7fb904a07 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 10:55:22 +0100 Subject: [PATCH 086/157] refactor(useKeyPress): update preventDefault handling --- packages/react/src/hooks/useKeyPress.ts | 14 ++++++++++++-- packages/system/src/utils/dom.ts | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index b2928baa..9dda2aff 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -8,6 +8,7 @@ type KeyOrCode = 'key' | 'code'; export type UseKeyPressOptions = { target?: Window | Document | HTMLElement | ShadowRoot | null; actInsideInputWithModifier?: boolean; + preventDefault?: boolean; }; const defaultDoc = typeof document !== 'undefined' ? document : null; @@ -88,7 +89,7 @@ export function useKeyPress( if (keyCode !== null) { const downHandler = (event: KeyboardEvent) => { - modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey; + modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey || event.altKey; const preventAction = (!modifierPressed.current || (modifierPressed.current && !options.actInsideInputWithModifier)) && isInputDOMNode(event); @@ -100,7 +101,16 @@ export function useKeyPress( pressedKeys.current.add(event[keyOrCode]); if (isMatchingKey(keyCodes, pressedKeys.current, false)) { - event.preventDefault(); + const target = (event.composedPath?.()?.[0] || event.target) as Element | null; + const isInteractiveElement = target?.nodeName === 'BUTTON' || target?.nodeName === 'A'; + + if ( + (options.preventDefault || typeof options.preventDefault === 'undefined') && + (modifierPressed.current || !isInteractiveElement) + ) { + event.preventDefault(); + } + setKeyPressed(true); } }; diff --git a/packages/system/src/utils/dom.ts b/packages/system/src/utils/dom.ts index 4195ea3a..2311153f 100644 --- a/packages/system/src/utils/dom.ts +++ b/packages/system/src/utils/dom.ts @@ -35,7 +35,7 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({ export const getHostForElement = (element: HTMLElement | EventTarget | null): Document | ShadowRoot => ((element as Partial | null)?.getRootNode?.() as Document | ShadowRoot) || window?.document; -const inputTags = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON']; +const inputTags = ['INPUT', 'SELECT', 'TEXTAREA']; export function isInputDOMNode(event: KeyboardEvent): boolean { // using composed path for handling shadow dom From 9b1c638de8569119519dc4d8a75d3b9adfa01ed0 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 11:00:22 +0100 Subject: [PATCH 087/157] refactor(useKeyPress): cleanup --- packages/react/src/hooks/useKeyPress.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index 9dda2aff..ec12e562 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -104,10 +104,7 @@ export function useKeyPress( const target = (event.composedPath?.()?.[0] || event.target) as Element | null; const isInteractiveElement = target?.nodeName === 'BUTTON' || target?.nodeName === 'A'; - if ( - (options.preventDefault || typeof options.preventDefault === 'undefined') && - (modifierPressed.current || !isInteractiveElement) - ) { + if (options.preventDefault !== false && (modifierPressed.current || !isInteractiveElement)) { event.preventDefault(); } From 5e810bc01c1e2c71687819460a0d9e6a5217db55 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 11:01:01 +0100 Subject: [PATCH 088/157] remove console.log --- packages/svelte/src/lib/store/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/svelte/src/lib/store/utils.ts b/packages/svelte/src/lib/store/utils.ts index 0d453c45..76b100b6 100644 --- a/packages/svelte/src/lib/store/utils.ts +++ b/packages/svelte/src/lib/store/utils.ts @@ -175,7 +175,6 @@ export const createNodesStore = ( console.log(nodesInitialized); if (get(fitViewQueued) && nodesInitialized && get(panZoom)) { - console.log('trying'); const fitViewPromise = fitViewport( { nodes: nodeLookup, From e078c55442bf363922aa70ecb6d1a812cf47435f Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 11:01:28 +0100 Subject: [PATCH 089/157] remove console.log --- packages/svelte/src/lib/store/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/svelte/src/lib/store/index.ts b/packages/svelte/src/lib/store/index.ts index b0d70a5e..83c6c623 100644 --- a/packages/svelte/src/lib/store/index.ts +++ b/packages/svelte/src/lib/store/index.ts @@ -144,7 +144,6 @@ export function createStore({ } function fitView(options?: FitViewOptions) { - console.log('fitView Store'); // We either create a new Promise or reuse the existing one // Even if fitView is called multiple times in a row, we only end up with a single Promise const fitViewResolver = get(store.fitViewResolver) ?? Promise.withResolvers(); From b0dc7baa802a8566cc2a0ff06703073894c4d2be Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 11:02:21 +0100 Subject: [PATCH 090/157] remove console.log --- packages/svelte/src/lib/store/utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/svelte/src/lib/store/utils.ts b/packages/svelte/src/lib/store/utils.ts index 76b100b6..e924d832 100644 --- a/packages/svelte/src/lib/store/utils.ts +++ b/packages/svelte/src/lib/store/utils.ts @@ -172,8 +172,6 @@ export const createNodesStore = ( checkEquality: false }); - console.log(nodesInitialized); - if (get(fitViewQueued) && nodesInitialized && get(panZoom)) { const fitViewPromise = fitViewport( { From ed1cb4da31481c4e556cad93ef1f88ecf6437507 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 11:06:57 +0100 Subject: [PATCH 091/157] use async function instead of .then --- packages/react/src/store/index.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index e099ca95..deb30c29 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -42,14 +42,14 @@ const createStore = ({ nodeExtent?: CoordinateExtent; }) => createWithEqualityFn((set, get) => { - function resolveFitView() { + async function resolveFitView() { const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); if (!panZoom) { return; } - const fitViewPromise = fitViewport( + const viewFitted = await fitViewport( { nodes: nodeLookup, width, @@ -60,10 +60,9 @@ const createStore = ({ }, fitViewOptions ); - fitViewPromise.then((value) => { - fitViewResolver?.resolve(value); - set({ fitViewResolver: null }); - }); + + fitViewResolver?.resolve(viewFitted); + set({ fitViewResolver: null }); } return { From 9be527606989152a66d9f3427487bb8ee6b4d92f Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 11:12:18 +0100 Subject: [PATCH 092/157] simplify resolveFitView --- packages/react/src/store/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index deb30c29..8ca0b050 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -49,7 +49,7 @@ const createStore = ({ return; } - const viewFitted = await fitViewport( + await fitViewport( { nodes: nodeLookup, width, @@ -61,7 +61,7 @@ const createStore = ({ fitViewOptions ); - fitViewResolver?.resolve(viewFitted); + fitViewResolver?.resolve(true); set({ fitViewResolver: null }); } From 3ac2846d5e359d18a2d9ccf6ae9c24c2a2e39b6d Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 27 Mar 2025 12:03:47 +0100 Subject: [PATCH 093/157] add comment --- packages/react/src/store/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 8ca0b050..8e64b51c 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -45,7 +45,7 @@ const createStore = ({ async function resolveFitView() { const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); - if (!panZoom) { + if (!panZoom || !fitViewResolver) { return; } @@ -61,7 +61,11 @@ const createStore = ({ fitViewOptions ); - fitViewResolver?.resolve(true); + fitViewResolver.resolve(true); + /** + * wait for the fitViewport to resolve before deleting the resolver, + * we want to reuse the old resolver if the user calls fitView again in the mean time + */ set({ fitViewResolver: null }); } From 8f45432378446f645e9789344300ce5142f90967 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Mar 2025 11:06:08 +0000 Subject: [PATCH 094/157] chore(packages): bump --- .changeset/empty-swans-exercise.md | 5 ---- .changeset/famous-impalas-relate.md | 6 ----- .changeset/forty-phones-lick.md | 5 ---- .changeset/fuzzy-cameras-nail.md | 5 ---- .changeset/great-pillows-drive.md | 5 ---- .changeset/healthy-baboons-judge.md | 5 ---- .changeset/hungry-shrimps-remain.md | 5 ---- .changeset/large-suns-notice.md | 5 ---- .changeset/polite-drinks-listen.md | 5 ---- .changeset/poor-poems-visit.md | 7 ------ .changeset/tame-bulldogs-juggle.md | 5 ---- .changeset/twenty-sloths-reflect.md | 6 ----- .changeset/unlucky-lobsters-refuse.md | 5 ---- .changeset/witty-toys-wash.md | 5 ---- packages/react/CHANGELOG.md | 33 +++++++++++++++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 13 +++++++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 10 ++++++++ packages/system/package.json | 2 +- 20 files changed, 59 insertions(+), 77 deletions(-) delete mode 100644 .changeset/empty-swans-exercise.md delete mode 100644 .changeset/famous-impalas-relate.md delete mode 100644 .changeset/forty-phones-lick.md delete mode 100644 .changeset/fuzzy-cameras-nail.md delete mode 100644 .changeset/great-pillows-drive.md delete mode 100644 .changeset/healthy-baboons-judge.md delete mode 100644 .changeset/hungry-shrimps-remain.md delete mode 100644 .changeset/large-suns-notice.md delete mode 100644 .changeset/polite-drinks-listen.md delete mode 100644 .changeset/poor-poems-visit.md delete mode 100644 .changeset/tame-bulldogs-juggle.md delete mode 100644 .changeset/twenty-sloths-reflect.md delete mode 100644 .changeset/unlucky-lobsters-refuse.md delete mode 100644 .changeset/witty-toys-wash.md diff --git a/.changeset/empty-swans-exercise.md b/.changeset/empty-swans-exercise.md deleted file mode 100644 index 8769d594..00000000 --- a/.changeset/empty-swans-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@xyflow/react": patch ---- - -fix: improve TSDoc comments for `BackgroundProps` diff --git a/.changeset/famous-impalas-relate.md b/.changeset/famous-impalas-relate.md deleted file mode 100644 index 318bcc30..00000000 --- a/.changeset/famous-impalas-relate.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/svelte': patch ---- - -Prevent onPaneClick when connection is in progress. Closes [#5057](https://github.com/xyflow/xyflow/issues/5057) diff --git a/.changeset/forty-phones-lick.md b/.changeset/forty-phones-lick.md deleted file mode 100644 index 86132fa3..00000000 --- a/.changeset/forty-phones-lick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@xyflow/react": patch ---- - -fix: improve TSDoc comments for `EdgeLabelOptions` and `BaseEdgeProps` diff --git a/.changeset/fuzzy-cameras-nail.md b/.changeset/fuzzy-cameras-nail.md deleted file mode 100644 index d2124f5d..00000000 --- a/.changeset/fuzzy-cameras-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@xyflow/react": patch ---- - -fix: improve TSDoc comments for `ControlProps` diff --git a/.changeset/great-pillows-drive.md b/.changeset/great-pillows-drive.md deleted file mode 100644 index 0b099cf8..00000000 --- a/.changeset/great-pillows-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Do not swallow key events when a button is focused diff --git a/.changeset/healthy-baboons-judge.md b/.changeset/healthy-baboons-judge.md deleted file mode 100644 index b31a6857..00000000 --- a/.changeset/healthy-baboons-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -fix: improve TSDoc comments for `NodeToolbarProps` diff --git a/.changeset/hungry-shrimps-remain.md b/.changeset/hungry-shrimps-remain.md deleted file mode 100644 index abf4ef75..00000000 --- a/.changeset/hungry-shrimps-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': minor ---- - -You can now express paddings in fitViewOptions as pixels ('30px'), as viewport percentages ('20%') and define different paddings for each side. diff --git a/.changeset/large-suns-notice.md b/.changeset/large-suns-notice.md deleted file mode 100644 index edef2e3a..00000000 --- a/.changeset/large-suns-notice.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -feat: export `EdgeLabelRendererProps` diff --git a/.changeset/polite-drinks-listen.md b/.changeset/polite-drinks-listen.md deleted file mode 100644 index 34be961a..00000000 --- a/.changeset/polite-drinks-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Add TSDoc annotations for exported edges diff --git a/.changeset/poor-poems-visit.md b/.changeset/poor-poems-visit.md deleted file mode 100644 index 8a258582..00000000 --- a/.changeset/poor-poems-visit.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/svelte': patch -'@xyflow/system': patch ---- - -Fix fitView not working immediately after adding new nodes diff --git a/.changeset/tame-bulldogs-juggle.md b/.changeset/tame-bulldogs-juggle.md deleted file mode 100644 index 1f915341..00000000 --- a/.changeset/tame-bulldogs-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -fix: improve TSDoc comments for `EdgeLabelOptions` and `EdgeTextProps` diff --git a/.changeset/twenty-sloths-reflect.md b/.changeset/twenty-sloths-reflect.md deleted file mode 100644 index fda503ae..00000000 --- a/.changeset/twenty-sloths-reflect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/svelte': patch ---- - -Hidden nodes are not displayed in the mini map anymore diff --git a/.changeset/unlucky-lobsters-refuse.md b/.changeset/unlucky-lobsters-refuse.md deleted file mode 100644 index e98d4c08..00000000 --- a/.changeset/unlucky-lobsters-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Release key even when an inout field is focused diff --git a/.changeset/witty-toys-wash.md b/.changeset/witty-toys-wash.md deleted file mode 100644 index 4f2972f6..00000000 --- a/.changeset/witty-toys-wash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Add center-left and center-right as a panel position diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index baa007ba..ca556d40 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,38 @@ # @xyflow/react +## 12.5.0 + +### Minor Changes + +- [#5067](https://github.com/xyflow/xyflow/pull/5067) [`acba901d`](https://github.com/xyflow/xyflow/commit/acba901d861aa84cb5beba60b24fff4cfde7ada6) Thanks [@peterkogo](https://github.com/peterkogo)! - You can now express paddings in fitViewOptions as pixels ('30px'), as viewport percentages ('20%') and define different paddings for each side. + +### Patch Changes + +- [#5109](https://github.com/xyflow/xyflow/pull/5109) [`0cdda42c`](https://github.com/xyflow/xyflow/commit/0cdda42cdd1cd43d43d43c44e54b7b9f7a716ca9) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: improve TSDoc comments for `BackgroundProps` + +- [#5059](https://github.com/xyflow/xyflow/pull/5059) [`065ff89d`](https://github.com/xyflow/xyflow/commit/065ff89d10488f9c76c56870511e45eaed299778) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Prevent onPaneClick when connection is in progress. Closes [#5057](https://github.com/xyflow/xyflow/issues/5057) + +- [#5110](https://github.com/xyflow/xyflow/pull/5110) [`7eb6eb07`](https://github.com/xyflow/xyflow/commit/7eb6eb0709e451d7628bfdbc3ced89b3bb57b626) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: improve TSDoc comments for `EdgeLabelOptions` and `BaseEdgeProps` + +- [#5113](https://github.com/xyflow/xyflow/pull/5113) [`bce8542d`](https://github.com/xyflow/xyflow/commit/bce8542df19c33f3cd9225f483435e8a7aa4ed94) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: improve TSDoc comments for `ControlProps` + +- [#5116](https://github.com/xyflow/xyflow/pull/5116) [`58942154`](https://github.com/xyflow/xyflow/commit/589421542386906ec49d8469cac551b8f7ea1c47) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: improve TSDoc comments for `NodeToolbarProps` + +- [#5114](https://github.com/xyflow/xyflow/pull/5114) [`ba2bfbb4`](https://github.com/xyflow/xyflow/commit/ba2bfbb49aafac979f94b0136bb408faea12d5c6) Thanks [@dimaMachina](https://github.com/dimaMachina)! - feat: export `EdgeLabelRendererProps` + +- [#5107](https://github.com/xyflow/xyflow/pull/5107) [`c5a8c237`](https://github.com/xyflow/xyflow/commit/c5a8c23773e5985be6b37abacdac743911be8c09) Thanks [@moklick](https://github.com/moklick)! - Add TSDoc annotations for exported edges + +- [#5067](https://github.com/xyflow/xyflow/pull/5067) [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix fitView not working immediately after adding new nodes + +- [#5115](https://github.com/xyflow/xyflow/pull/5115) [`c2154557`](https://github.com/xyflow/xyflow/commit/c215455735385ef5e12e4130164b9d01f9c18aa2) Thanks [@dimaMachina](https://github.com/dimaMachina)! - fix: improve TSDoc comments for `EdgeLabelOptions` and `EdgeTextProps` + +- [#5093](https://github.com/xyflow/xyflow/pull/5093) [`65825e89`](https://github.com/xyflow/xyflow/commit/65825e89a6e2e7591087eb41ac89da4da7095f8f) Thanks [@moklick](https://github.com/moklick)! - Hidden nodes are not displayed in the mini map anymore + +- [#5090](https://github.com/xyflow/xyflow/pull/5090) [`8da1748a`](https://github.com/xyflow/xyflow/commit/8da1748a6ad5cdde9f03737ff786bd29c9c968de) Thanks [@moklick](https://github.com/moklick)! - Release key even when an inout field is focused + +- Updated dependencies [[`5d15b01b`](https://github.com/xyflow/xyflow/commit/5d15b01ba8cb349d6397a6ed8162848b4dfec293), [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe), [`a79f30b3`](https://github.com/xyflow/xyflow/commit/a79f30b3dd7c8ff6400c8d22214b2c2282e5bac1)]: + - @xyflow/system@0.0.53 + ## 12.4.4 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 5e4d41df..476b277e 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.4.4", + "version": "12.5.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 12446c10..fa5bc372 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,18 @@ # @xyflow/svelte +## 0.1.32 + +### Patch Changes + +- [#5059](https://github.com/xyflow/xyflow/pull/5059) [`065ff89d`](https://github.com/xyflow/xyflow/commit/065ff89d10488f9c76c56870511e45eaed299778) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - Prevent onPaneClick when connection is in progress. Closes [#5057](https://github.com/xyflow/xyflow/issues/5057) + +- [#5067](https://github.com/xyflow/xyflow/pull/5067) [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix fitView not working immediately after adding new nodes + +- [#5093](https://github.com/xyflow/xyflow/pull/5093) [`65825e89`](https://github.com/xyflow/xyflow/commit/65825e89a6e2e7591087eb41ac89da4da7095f8f) Thanks [@moklick](https://github.com/moklick)! - Hidden nodes are not displayed in the mini map anymore + +- Updated dependencies [[`5d15b01b`](https://github.com/xyflow/xyflow/commit/5d15b01ba8cb349d6397a6ed8162848b4dfec293), [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe), [`a79f30b3`](https://github.com/xyflow/xyflow/commit/a79f30b3dd7c8ff6400c8d22214b2c2282e5bac1)]: + - @xyflow/system@0.0.53 + ## 0.1.31 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index e41037a7..c917755c 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.31", + "version": "0.1.32", "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 d4fc2de0..0c193291 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,15 @@ # @xyflow/system +## 0.0.53 + +### Patch Changes + +- [#5118](https://github.com/xyflow/xyflow/pull/5118) [`5d15b01b`](https://github.com/xyflow/xyflow/commit/5d15b01ba8cb349d6397a6ed8162848b4dfec293) Thanks [@moklick](https://github.com/moklick)! - Do not swallow key events when a button is focused + +- [#5067](https://github.com/xyflow/xyflow/pull/5067) [`cb685281`](https://github.com/xyflow/xyflow/commit/cb685281d0eaf03e9833271c31f92b1d143af2fe) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix fitView not working immediately after adding new nodes + +- [#5091](https://github.com/xyflow/xyflow/pull/5091) [`a79f30b3`](https://github.com/xyflow/xyflow/commit/a79f30b3dd7c8ff6400c8d22214b2c2282e5bac1) Thanks [@moklick](https://github.com/moklick)! - Add center-left and center-right as a panel position + ## 0.0.52 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index f23d4c73..ed8f3c06 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.52", + "version": "0.0.53", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From 77b24e7f3a6c149875bc071da94b976ea11fbf88 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 13:17:46 +0100 Subject: [PATCH 095/157] fix(fitView): handle uncontrolled flows --- packages/react/src/store/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 8e64b51c..cffc9644 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -45,7 +45,7 @@ const createStore = ({ async function resolveFitView() { const { nodeLookup, panZoom, fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); - if (!panZoom || !fitViewResolver) { + if (!panZoom) { return; } @@ -61,7 +61,7 @@ const createStore = ({ fitViewOptions ); - fitViewResolver.resolve(true); + fitViewResolver?.resolve(true); /** * wait for the fitViewport to resolve before deleting the resolver, * we want to reuse the old resolver if the user calls fitView again in the mean time @@ -89,6 +89,7 @@ const createStore = ({ checkEquality: true, }); + console.log(fitViewQueued, nodesInitialized); if (fitViewQueued && nodesInitialized) { resolveFitView(); set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); From 6dfea6863a3cbd91f932bf54a6dba549bd248bd5 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 13:18:17 +0100 Subject: [PATCH 096/157] chore(changeset): add --- .changeset/lovely-rabbits-yawn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lovely-rabbits-yawn.md diff --git a/.changeset/lovely-rabbits-yawn.md b/.changeset/lovely-rabbits-yawn.md new file mode 100644 index 00000000..06432dfb --- /dev/null +++ b/.changeset/lovely-rabbits-yawn.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Handle fitView for uncontrolled flows From 150549cd4fa767b006201b430ea870692aad537e Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 13:20:57 +0100 Subject: [PATCH 097/157] chore(store): cleanup --- packages/react/src/store/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index cffc9644..924e83cf 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -89,7 +89,6 @@ const createStore = ({ checkEquality: true, }); - console.log(fitViewQueued, nodesInitialized); if (fitViewQueued && nodesInitialized) { resolveFitView(); set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); From 95854aa7319a32836cac2d9f03cde84bcd7bbd53 Mon Sep 17 00:00:00 2001 From: moklick Date: Thu, 27 Mar 2025 13:29:08 +0100 Subject: [PATCH 098/157] chore(tests): adjust pan test --- tests/playwright/e2e/pane.spec.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/playwright/e2e/pane.spec.ts b/tests/playwright/e2e/pane.spec.ts index 802e0139..4c27e33c 100644 --- a/tests/playwright/e2e/pane.spec.ts +++ b/tests/playwright/e2e/pane.spec.ts @@ -20,18 +20,21 @@ test.describe('Pane default', () => { await expect(pane).toBeAttached(); const paneBox = await pane.boundingBox(); - const transformsBefore = await getTransform(viewport); + const movementPx = 100; await pane.hover(); await page.mouse.down(); // Move pane by 100, 100 - await page.mouse.move(paneBox!.x + paneBox!.width * 0.5 + 100, paneBox!.y + paneBox!.height * 0.5 + 100); + await page.mouse.move( + paneBox!.x + paneBox!.width * 0.5 + movementPx, + paneBox!.y + paneBox!.height * 0.5 + movementPx + ); const transformsAfter = await getTransform(viewport); - expect(Math.floor(transformsAfter.translateX - transformsBefore.translateX)).toBe(100); - expect(Math.floor(transformsAfter.translateY - transformsBefore.translateY)).toBe(100); + expect(movementPx - Math.floor(transformsAfter.translateX - transformsBefore.translateX)).toBeLessThan(1); + expect(movementPx - Math.floor(transformsAfter.translateY - transformsBefore.translateY)).toBeLessThan(1); }); test('scrolling the default pane zooms it', async ({ page }) => { From 959742f4998126444d88d28130decb0b59afbd23 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Mar 2025 12:31:08 +0000 Subject: [PATCH 099/157] chore(packages): bump --- .changeset/lovely-rabbits-yawn.md | 5 ----- packages/react/CHANGELOG.md | 6 ++++++ packages/react/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/lovely-rabbits-yawn.md diff --git a/.changeset/lovely-rabbits-yawn.md b/.changeset/lovely-rabbits-yawn.md deleted file mode 100644 index 06432dfb..00000000 --- a/.changeset/lovely-rabbits-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Handle fitView for uncontrolled flows diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index ca556d40..57ba35f4 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,11 @@ # @xyflow/react +## 12.5.1 + +### Patch Changes + +- [#5120](https://github.com/xyflow/xyflow/pull/5120) [`6dfea686`](https://github.com/xyflow/xyflow/commit/6dfea6863a3cbd91f932bf54a6dba549bd248bd5) Thanks [@moklick](https://github.com/moklick)! - Handle fitView for uncontrolled flows + ## 12.5.0 ### Minor Changes diff --git a/packages/react/package.json b/packages/react/package.json index 476b277e..bc7b90bb 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.0", + "version": "12.5.1", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", From 0d4dab177111ba0460fb9cb34be8eeeb01dc580b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Olav=20Salvesen?= Date: Sat, 29 Mar 2025 12:40:03 +0100 Subject: [PATCH 100/157] chore: add missing type re-export for NodeConnection --- packages/react/src/index.ts | 1 + packages/svelte/src/lib/index.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 1cb3764c..eb106f18 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -106,6 +106,7 @@ export { type FinalConnectionState, type ConnectionInProgress, type NoConnection, + type NodeConnection, } from '@xyflow/system'; // we need this workaround to prevent a duplicate identifier error diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index 3e96210b..25eb0f9c 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -109,7 +109,8 @@ export { type ResizeParams, type ResizeParamsWithDirection, type ResizeDragEvent, - type IsValidConnection + type IsValidConnection, + type NodeConnection } from '@xyflow/system'; // system utils From b76f7f9eb4841f139b1468b8eda0430ddd19a1ae Mon Sep 17 00:00:00 2001 From: moklick Date: Sun, 30 Mar 2025 17:20:48 +0200 Subject: [PATCH 101/157] chore(changeset): add --- .changeset/fifty-lizards-smash.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/fifty-lizards-smash.md diff --git a/.changeset/fifty-lizards-smash.md b/.changeset/fifty-lizards-smash.md new file mode 100644 index 00000000..22255569 --- /dev/null +++ b/.changeset/fifty-lizards-smash.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/svelte': patch +--- + +Export NodeConnection type From b1502dc2dc691b85d04a90a82ad55d32f701dd85 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 31 Mar 2025 11:52:43 +0200 Subject: [PATCH 102/157] Dont call onNodesChange when there are no changes & call setNodes instead --- .../src/components/BatchProvider/index.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 0ef7e399..8a7d289a 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -28,7 +28,7 @@ export function BatchProvider(); const nodeQueueHandler = useCallback((queueItems: QueueItem[]) => { - const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup } = store.getState(); + const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup, fitViewQueued } = store.getState(); /* * This is essentially an `Array.reduce` in imperative clothing. Processing @@ -43,12 +43,17 @@ export function BatchProvider[] - ); + const changes = getElementsDiffChanges({ + items: next, + lookup: nodeLookup, + }) as NodeChange[]; + 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. + setNodes(next); + } } }, []); const nodeQueue = useQueue(nodeQueueHandler); From 3079c2c911426f54e8d295083ddbe97ed3aad201 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 31 Mar 2025 11:55:11 +0200 Subject: [PATCH 103/157] add changeset --- .changeset/thirty-terms-grow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thirty-terms-grow.md diff --git a/.changeset/thirty-terms-grow.md b/.changeset/thirty-terms-grow.md new file mode 100644 index 00000000..a2f00e1f --- /dev/null +++ b/.changeset/thirty-terms-grow.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Fix `fitView` not working when returning early in `onNodesChange`. From aa873d6ddc69011c49a355f9b0c640d03dde3cfc Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 31 Mar 2025 13:47:15 +0200 Subject: [PATCH 104/157] enhance fitView scheduling --- packages/react/src/components/BatchProvider/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 8a7d289a..382324da 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -52,7 +52,12 @@ export function BatchProvider { + const { fitViewQueued, nodes, setNodes } = store.getState(); + if (fitViewQueued) { + setNodes(nodes); + } + }); } } }, []); From 742bfe345a9d56c4f3160e997cf32d1a960c8dd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 31 Mar 2025 12:53:58 +0000 Subject: [PATCH 105/157] chore(packages): bump --- .changeset/fifty-lizards-smash.md | 6 ------ .changeset/thirty-terms-grow.md | 5 ----- packages/react/CHANGELOG.md | 8 ++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 6 ++++++ packages/svelte/package.json | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) delete mode 100644 .changeset/fifty-lizards-smash.md delete mode 100644 .changeset/thirty-terms-grow.md diff --git a/.changeset/fifty-lizards-smash.md b/.changeset/fifty-lizards-smash.md deleted file mode 100644 index 22255569..00000000 --- a/.changeset/fifty-lizards-smash.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/svelte': patch ---- - -Export NodeConnection type diff --git a/.changeset/thirty-terms-grow.md b/.changeset/thirty-terms-grow.md deleted file mode 100644 index a2f00e1f..00000000 --- a/.changeset/thirty-terms-grow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Fix `fitView` not working when returning early in `onNodesChange`. diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 57ba35f4..cd226ab7 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,13 @@ # @xyflow/react +## 12.5.2 + +### Patch Changes + +- [#5124](https://github.com/xyflow/xyflow/pull/5124) [`b76f7f9e`](https://github.com/xyflow/xyflow/commit/b76f7f9eb4841f139b1468b8eda0430ddd19a1ae) Thanks [@bjornosal](https://github.com/bjornosal)! - Export NodeConnection type + +- [#5127](https://github.com/xyflow/xyflow/pull/5127) [`3079c2c9`](https://github.com/xyflow/xyflow/commit/3079c2c911426f54e8d295083ddbe97ed3aad201) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix `fitView` not working when returning early in `onNodesChange`. + ## 12.5.1 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index bc7b90bb..2bda6653 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.1", + "version": "12.5.2", "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 fa5bc372..926d6bb7 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # @xyflow/svelte +## 0.1.33 + +### Patch Changes + +- [#5124](https://github.com/xyflow/xyflow/pull/5124) [`b76f7f9e`](https://github.com/xyflow/xyflow/commit/b76f7f9eb4841f139b1468b8eda0430ddd19a1ae) Thanks [@bjornosal](https://github.com/bjornosal)! - Export NodeConnection type + ## 0.1.32 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index c917755c..7fe3b7da 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.32", + "version": "0.1.33", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "keywords": [ "svelte", From aae3f49eec34633f7fb977e83b46057f8407c22f Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 1 Apr 2025 12:39:42 +0200 Subject: [PATCH 106/157] make fitView fire even when onNodesChange is not implmented --- packages/react/src/components/BatchProvider/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/react/src/components/BatchProvider/index.tsx b/packages/react/src/components/BatchProvider/index.tsx index 382324da..f41b79a8 100644 --- a/packages/react/src/components/BatchProvider/index.tsx +++ b/packages/react/src/components/BatchProvider/index.tsx @@ -42,13 +42,16 @@ export function BatchProvider[]; + + // We only want to fire onNodesChange if there are changes to the nodes if (changes.length > 0) { - onNodesChange(changes); + 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. @@ -61,6 +64,7 @@ export function BatchProvider(nodeQueueHandler); const edgeQueueHandler = useCallback((queueItems: QueueItem[]) => { From 75ab89420e3cd0fdc34baf06eabdc50113d4de7c Mon Sep 17 00:00:00 2001 From: peterkogo Date: Tue, 1 Apr 2025 12:40:28 +0200 Subject: [PATCH 107/157] add changeset --- .changeset/gentle-walls-hammer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gentle-walls-hammer.md diff --git a/.changeset/gentle-walls-hammer.md b/.changeset/gentle-walls-hammer.md new file mode 100644 index 00000000..21f4f3be --- /dev/null +++ b/.changeset/gentle-walls-hammer.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Fix fitView not working when onNodesChange is not defined. From 8adca80945ef5e7ff80cb7c8d15eb5bca527c3c0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 1 Apr 2025 10:42:51 +0000 Subject: [PATCH 108/157] chore(packages): bump --- .changeset/gentle-walls-hammer.md | 5 ----- packages/react/CHANGELOG.md | 6 ++++++ packages/react/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/gentle-walls-hammer.md diff --git a/.changeset/gentle-walls-hammer.md b/.changeset/gentle-walls-hammer.md deleted file mode 100644 index 21f4f3be..00000000 --- a/.changeset/gentle-walls-hammer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Fix fitView not working when onNodesChange is not defined. diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index cd226ab7..7c4ba5db 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,11 @@ # @xyflow/react +## 12.5.3 + +### Patch Changes + +- [#5132](https://github.com/xyflow/xyflow/pull/5132) [`75ab8942`](https://github.com/xyflow/xyflow/commit/75ab89420e3cd0fdc34baf06eabdc50113d4de7c) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix fitView not working when onNodesChange is not defined. + ## 12.5.2 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 2bda6653..8057a940 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.2", + "version": "12.5.3", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", From 7acab1e123944c296180fbf826a3fd488963608f Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:36:00 +0200 Subject: [PATCH 109/157] fix `@default` TSDoc tags for `BackgroundProps` --- .changeset/eleven-spoons-attend.md | 5 +++++ .../additional-components/Background/types.ts | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .changeset/eleven-spoons-attend.md diff --git a/.changeset/eleven-spoons-attend.md b/.changeset/eleven-spoons-attend.md new file mode 100644 index 00000000..d18ccf0c --- /dev/null +++ b/.changeset/eleven-spoons-attend.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix `@default` TSDoc tags for `BackgroundProps` diff --git a/packages/react/src/additional-components/Background/types.ts b/packages/react/src/additional-components/Background/types.ts index d805a91c..8e8bf944 100644 --- a/packages/react/src/additional-components/Background/types.ts +++ b/packages/react/src/additional-components/Background/types.ts @@ -18,18 +18,18 @@ export enum BackgroundVariant { export type BackgroundProps = { /** When multiple backgrounds are present on the page, each one should have a unique id. */ id?: string; - /** Color of the pattern */ + /** Color of the pattern. */ color?: string; - /** Color of the background */ + /** Color of the background. */ bgColor?: string; - /** Class applied to the container */ + /** Class applied to the container. */ className?: string; - /** Class applied to the pattern */ + /** Class applied to the pattern. */ patternClassName?: string; /** * The gap between patterns. Passing in a tuple allows you to control the x and y gap * independently. - * @default '28' + * @default 20 */ gap?: number | [number, number]; /** @@ -39,8 +39,8 @@ export type BackgroundProps = { */ size?: number; /** - * Offset of the pattern - * @default 2 + * Offset of the pattern. + * @default 0 */ offset?: number | [number, number]; /** @@ -49,12 +49,12 @@ export type BackgroundProps = { */ lineWidth?: number; /** - * Variant of the pattern + * Variant of the pattern. * @default BackgroundVariant.Dots * @example BackgroundVariant.Lines, BackgroundVariant.Dots, BackgroundVariant.Cross * 'lines', 'dots', 'cross' */ variant?: BackgroundVariant; - /** Style applied to the container */ + /** Style applied to the container. */ style?: CSSProperties; }; From 754a167134f22fa00a139de4c7e10aaaa1953ac8 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:38:33 +0200 Subject: [PATCH 110/157] fix: improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` --- .changeset/flat-taxis-provide.md | 5 ++ .../NodeResizer/types.ts | 55 +++++++++++++------ 2 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 .changeset/flat-taxis-provide.md diff --git a/.changeset/flat-taxis-provide.md b/.changeset/flat-taxis-provide.md new file mode 100644 index 00000000..d9856d36 --- /dev/null +++ b/.changeset/flat-taxis-provide.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` diff --git a/packages/react/src/additional-components/NodeResizer/types.ts b/packages/react/src/additional-components/NodeResizer/types.ts index 1295440f..e34329b1 100644 --- a/packages/react/src/additional-components/NodeResizer/types.ts +++ b/packages/react/src/additional-components/NodeResizer/types.ts @@ -14,39 +14,57 @@ import type { */ export type NodeResizerProps = { /** - * Id of the node it is resizing + * Id of the node it is resizing. * @remarks optional if used inside custom node */ nodeId?: string; - /** Color of the resize handle */ + /** Color of the resize handle. */ color?: string; - /** ClassName applied to handle */ + /** Class name applied to handle. */ handleClassName?: string; - /** Style applied to handle */ + /** Style applied to handle. */ handleStyle?: CSSProperties; - /** ClassName applied to line */ + /** Class name applied to line. */ lineClassName?: string; - /** Style applied to line */ + /** Style applied to line. */ lineStyle?: CSSProperties; - /** Are the controls visible */ + /** + * Are the controls visible. + * @default true + */ isVisible?: boolean; - /** Minimum width of node */ + /** + * Minimum width of node. + * @default 10 + */ minWidth?: number; - /** Minimum height of node */ + /** + * Minimum height of node. + * @default 10 + */ minHeight?: number; - /** Maximum width of node */ + /** + * Maximum width of node. + * @default Number.MAX_VALUE + */ maxWidth?: number; - /** Maximum height of node */ + /** + * Maximum height of node. + * @default Number.MAX_VALUE + */ maxHeight?: number; - /** Keep aspect ratio when resizing */ + /** + * Keep aspect ratio when resizing. + * @default false + */ keepAspectRatio?: boolean; - /** Callback to determine if node should resize */ + /** Callback to determine if node should resize. */ shouldResize?: ShouldResize; - /** Callback called when resizing starts */ + /** Callback called when resizing starts. */ onResizeStart?: OnResizeStart; - /** Callback called when resizing */ + /** Callback called when resizing. */ onResize?: OnResize; - /** Callback called when resizing ends */ + /** Callback called when resizing ends. */ onResizeEnd?: OnResizeEnd; }; @@ -68,13 +86,14 @@ export type ResizeControlProps = Pick< | 'onResizeEnd' > & { /** - * Position of the control + * Position of the control. * @example ControlPosition.TopLeft, ControlPosition.TopRight, * ControlPosition.BottomLeft, ControlPosition.BottomRight */ position?: ControlPosition; /** - * Variant of the control + * Variant of the control. + * @default "handle" * @example ResizeControlVariant.Handle, ResizeControlVariant.Line */ variant?: ResizeControlVariant; From 36657cd66322c911e87eb37275c584a80025adfe Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:40:41 +0200 Subject: [PATCH 111/157] fix: improve TSDoc comments for `EdgeBase` --- .changeset/itchy-terms-carry.md | 5 +++++ packages/system/src/types/edges.ts | 29 +++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) create mode 100644 .changeset/itchy-terms-carry.md diff --git a/.changeset/itchy-terms-carry.md b/.changeset/itchy-terms-carry.md new file mode 100644 index 00000000..f7760c4d --- /dev/null +++ b/.changeset/itchy-terms-carry.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +fix: improve TSDoc comments for `EdgeBase` diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index 76382e73..c0568200 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -4,44 +4,41 @@ export type EdgeBase< EdgeData extends Record = Record, EdgeType extends string | undefined = string | undefined > = { - /** Unique id of an edge */ + /** Unique id of an edge. */ id: string; - /** Type of an edge defined in edgeTypes */ + /** Type of edge defined in `edgeTypes`. */ type?: EdgeType; - /** Id of source node */ + /** Id of source node. */ source: string; - /** Id of target node */ + /** Id of target node. */ target: string; - /** - * Id of source handle - * only needed if there are multiple handles per node - */ + /** Id of source handle, only needed if there are multiple handles per node. */ sourceHandle?: string | null; - /** - * Id of target handle - * only needed if there are multiple handles per node - */ + /** Id of target handle, only needed if there are multiple handles per node. */ targetHandle?: string | null; animated?: boolean; hidden?: boolean; deletable?: boolean; selectable?: boolean; - /** Arbitrary data passed to an edge */ + /** Arbitrary data passed to an edge. */ data?: EdgeData; selected?: boolean; /** - * Set the marker on the beginning of an edge + * Set the marker on the beginning of an edge. * @example 'arrow', 'arrowclosed' or custom marker */ markerStart?: EdgeMarkerType; /** - * Set the marker on the end of an edge + * Set the marker on the end of an edge. * @example 'arrow', 'arrowclosed' or custom marker */ markerEnd?: EdgeMarkerType; zIndex?: number; ariaLabel?: string; - /** Padding around the edge where interaction is still possible */ + /** + * ReactFlow renders an invisible path around each edge to make them easier to click or tap on. + * This property sets the width of that invisible path. + */ interactionWidth?: number; }; From f0f378e5b6918c2c30d9dc1e32587063cb942d4e Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:46:13 +0200 Subject: [PATCH 112/157] fix: improve TSDoc comments for `Connection` and `ConnectionInProgress` --- .changeset/tall-knives-wink.md | 5 +++++ packages/system/src/types/general.ts | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 .changeset/tall-knives-wink.md diff --git a/.changeset/tall-knives-wink.md b/.changeset/tall-knives-wink.md new file mode 100644 index 00000000..c6b2f9b3 --- /dev/null +++ b/.changeset/tall-knives-wink.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +fix: improve TSDoc comments for `Connection` and `ConnectionInProgress` diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index ac0d95b7..a2fba7dd 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -33,9 +33,13 @@ export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => Promise = { + /** Indicates whether a connection is currently in progress. */ inProgress: true; + /** + * If an ongoing connection is above a handle or inside the connection radius, this will be `true` + * or `false`, otherwise `null`. + */ isValid: boolean | null; + /** Returns the xy start position or `null` if no connection is in progress. */ from: XYPosition; + /** Returns the start handle or `null` if no connection is in progress. */ fromHandle: Handle; + /** Returns the side (called position) of the start handle or `null` if no connection is in progress. */ fromPosition: Position; + /** Returns the start node or `null` if no connection is in progress. */ fromNode: NodeType; + /** Returns the xy end position or `null` if no connection is in progress. */ to: XYPosition; + /** Returns the end handle or `null` if no connection is in progress. */ toHandle: Handle | null; + /** Returns the side (called position) of the end handle or `null` if no connection is in progress. */ toPosition: Position; + /** Returns the end node or `null` if no connection is in progress. */ toNode: NodeType | null; }; From d4eb8d52d0e26e9534ec5fc347211ce91d1ddd32 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:49:08 +0200 Subject: [PATCH 113/157] fix: improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` --- .changeset/pink-toes-care.md | 5 +++++ .../additional-components/NodeToolbar/types.ts | 11 ++++++----- packages/react/src/types/general.ts | 17 +++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 .changeset/pink-toes-care.md diff --git a/.changeset/pink-toes-care.md b/.changeset/pink-toes-care.md new file mode 100644 index 00000000..67f016a0 --- /dev/null +++ b/.changeset/pink-toes-care.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` diff --git a/packages/react/src/additional-components/NodeToolbar/types.ts b/packages/react/src/additional-components/NodeToolbar/types.ts index 96756983..6655547d 100644 --- a/packages/react/src/additional-components/NodeToolbar/types.ts +++ b/packages/react/src/additional-components/NodeToolbar/types.ts @@ -10,12 +10,12 @@ export type NodeToolbarProps = HTMLAttributes & { * of nodes. */ nodeId?: string | string[]; - /** If true, node toolbar is visible even if node is not selected */ + /** If `true`, node toolbar is visible even if node is not selected. */ isVisible?: boolean; /** - * Position of the toolbar relative to the node - * @example Position.TopLeft, Position.TopRight, - * Position.BottomLeft, Position.BottomRight + * Position of the toolbar relative to the node. + * @default Position.Top + * @example Position.TopLeft, Position.TopRight, Position.BottomLeft, Position.BottomRight */ position?: Position; /** @@ -24,7 +24,8 @@ export type NodeToolbarProps = HTMLAttributes & { */ offset?: number; /** - * Align the toolbar relative to the node + * Align the toolbar relative to the node. + * @default "center" * @example Align.Start, Align.Center, Align.End */ align?: Align; diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 11021b3a..98302a86 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -131,14 +131,15 @@ export type ViewportHelperFunctions = { */ zoomOut: ZoomInOut; /** - * Sets the current zoom level. + * Zoom the viewport to a given zoom level. Passing in a `duration` will animate the viewport to + * the new zoom level. * * @param zoomLevel - the zoom level to set * @param options.duration - optional duration. If set, a transition will be applied */ zoomTo: ZoomTo; /** - * Returns the current zoom level. + * Get the current zoom level of the viewport. * * @returns current zoom as a number */ @@ -157,7 +158,8 @@ export type ViewportHelperFunctions = { */ getViewport: GetViewport; /** - * Sets the center of the view to the given position. + * Center the viewport on a given position. Passing in a `duration` will animate the viewport to + * the new position. * * @param x - x position * @param y - y position @@ -165,14 +167,17 @@ export type ViewportHelperFunctions = { */ setCenter: SetCenter; /** - * Fits the view to the given bounds . + * A low-level utility function to fit the viewport to a given rectangle. By passing in a + * `duration`, the viewport will animate from its current position to the new position. The + * `padding` option can be used to add space around the bounds. * * @param bounds - the bounds ({ x: number, y: number, width: number, height: number }) to fit the view to * @param options.padding - optional padding */ fitBounds: FitBounds; /** - * Converts a screen / client position to a flow position. + * With this function you can translate a screen pixel position to a flow position. It is useful + * for implementing drag and drop from a sidebar for example. * * @param clientPosition - the screen / client position. When you are working with events you can use event.clientX and event.clientY * @param options.snapToGrid - if true, the converted position will be snapped to the grid @@ -183,7 +188,7 @@ export type ViewportHelperFunctions = { */ screenToFlowPosition: (clientPosition: XYPosition, options?: { snapToGrid: boolean }) => XYPosition; /** - * Converts a flow position to a screen / client position. + * Translate a position inside the flow's canvas to a screen pixel position. * * @param flowPosition - the screen / client position. When you are working with events you can use event.clientX and event.clientY * @returns position as { x: number, y: number } From 89de9ca83fbf9263a687a0f5f915efb2beb31654 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:52:26 +0200 Subject: [PATCH 114/157] fix: improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` --- .changeset/silly-buckets-relate.md | 6 ++++++ .../svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte | 2 +- packages/system/src/styles/init.css | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 .changeset/silly-buckets-relate.md diff --git a/.changeset/silly-buckets-relate.md b/.changeset/silly-buckets-relate.md new file mode 100644 index 00000000..99e6bc91 --- /dev/null +++ b/.changeset/silly-buckets-relate.md @@ -0,0 +1,6 @@ +--- +'@xyflow/svelte': patch +'@xyflow/system': patch +--- + +fix: use `rgba` for colors with opacity instead of `rgb` diff --git a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte index f1a7a444..d9bee5d3 100644 --- a/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte +++ b/packages/svelte/src/lib/container/SvelteFlow/SvelteFlow.svelte @@ -297,7 +297,7 @@ --background-color-default: #fff; --background-pattern-color-default: #ddd; - --minimap-mask-color-default: rgb(240, 240, 240, 0.6); + --minimap-mask-color-default: rgba(240, 240, 240, 0.6); --minimap-mask-stroke-color-default: none; --minimap-mask-stroke-width-default: 1; diff --git a/packages/system/src/styles/init.css b/packages/system/src/styles/init.css index b0651116..ca4d6de7 100644 --- a/packages/system/src/styles/init.css +++ b/packages/system/src/styles/init.css @@ -13,7 +13,7 @@ --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5); --xy-minimap-background-color-default: #fff; - --xy-minimap-mask-background-color-default: rgb(240, 240, 240, 0.6); + --xy-minimap-mask-background-color-default: rgba(240, 240, 240, 0.6); --xy-minimap-mask-stroke-color-default: transparent; --xy-minimap-mask-stroke-width-default: 1; --xy-minimap-node-background-color-default: #e2e2e2; @@ -37,7 +37,7 @@ --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25); --xy-minimap-background-color-default: #141414; - --xy-minimap-mask-background-color-default: rgb(60, 60, 60, 0.6); + --xy-minimap-mask-background-color-default: rgba(60, 60, 60, 0.6); --xy-minimap-mask-stroke-color-default: transparent; --xy-minimap-mask-stroke-width-default: 1; --xy-minimap-node-background-color-default: #2b2b2b; From 82e6860e1354b8bb8047399b7773fd090be206d7 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 20:55:17 +0200 Subject: [PATCH 115/157] fix: improve TSDoc comments for `MiniMapProps` and `PanelProps` --- .changeset/grumpy-toes-sniff.md | 5 ++ .../additional-components/MiniMap/types.ts | 84 ++++++++++++++----- packages/react/src/components/Panel/index.tsx | 6 +- 3 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 .changeset/grumpy-toes-sniff.md diff --git a/.changeset/grumpy-toes-sniff.md b/.changeset/grumpy-toes-sniff.md new file mode 100644 index 00000000..70cb871d --- /dev/null +++ b/.changeset/grumpy-toes-sniff.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `MiniMapProps` and `PanelProps` diff --git a/packages/react/src/additional-components/MiniMap/types.ts b/packages/react/src/additional-components/MiniMap/types.ts index 8416f835..02513b10 100644 --- a/packages/react/src/additional-components/MiniMap/types.ts +++ b/packages/react/src/additional-components/MiniMap/types.ts @@ -10,47 +10,93 @@ export type GetMiniMapNodeAttribute = (node: NodeT * @expand */ export type MiniMapProps = Omit, 'onClick'> & { - /** Color of nodes on minimap */ + /** + * Color of nodes on minimap. + * @default "#e2e2e2" + */ nodeColor?: string | GetMiniMapNodeAttribute; - /** Stroke color of nodes on minimap */ + /** + * Stroke color of nodes on minimap. + * @default "transparent" + */ nodeStrokeColor?: string | GetMiniMapNodeAttribute; - /** ClassName applied to nodes on minimap */ + /** + * Class name applied to nodes on minimap. + * @default "" + */ nodeClassName?: string | GetMiniMapNodeAttribute; - /** Border radius of nodes on minimap */ + /** + * Border radius of nodes on minimap. + * @default 5 + */ nodeBorderRadius?: number; - /** Stroke width of nodes on minimap */ + /** + * Stroke width of nodes on minimap. + * @default 2 + */ nodeStrokeWidth?: number; - /** Component used to render nodes on minimap */ + /** + * A custom component to render the nodes in the minimap. This component must render an SVG + * element! + */ nodeComponent?: ComponentType; - /** Background color of minimap */ + /** Background color of minimap. */ bgColor?: string; - /** Color of mask representing viewport */ + /** + * The color of the mask that covers the portion of the minimap not currently visible in the + * viewport. + * @default "rgba(240, 240, 240, 0.6)" + */ maskColor?: string; - /** Stroke color of mask representing viewport */ + /** + * Stroke color of mask representing viewport. + * @default transparent + */ maskStrokeColor?: string; - /** Stroke width of mask representing viewport */ + /** + * Stroke width of mask representing viewport. + * @default 1 + */ maskStrokeWidth?: number; /** - * Position of minimap on pane + * Position of minimap on pane. + * @default PanelPosition.BottomRight * @example PanelPosition.TopLeft, PanelPosition.TopRight, * PanelPosition.BottomLeft, PanelPosition.BottomRight */ position?: PanelPosition; - /** Callback caled when minimap is clicked*/ + /** Callback called when minimap is clicked. */ onClick?: (event: MouseEvent, position: XYPosition) => void; - /** Callback called when node on minimap is clicked */ + /** Callback called when node on minimap is clicked. */ onNodeClick?: (event: MouseEvent, node: NodeType) => void; - /** If true, viewport is pannable via mini map component */ + /** + * Determines whether you can pan the viewport by dragging inside the minimap. + * @default false + */ pannable?: boolean; - /** If true, viewport is zoomable via mini map component */ + /** + * Determines whether you can zoom the viewport by scrolling inside the minimap. + * @default false + */ zoomable?: boolean; - /** The aria-label attribute */ + /** + * There is no text inside the minimap for a screen reader to use as an accessible name, so it's + * important we provide one to make the minimap accessible. The default is sufficient, but you may + * want to replace it with something more relevant to your app or product. + * @default "React Flow mini map" + */ ariaLabel?: string | null; - /** Invert direction when panning the minimap viewport */ + /** Invert direction when panning the minimap viewport. */ inversePan?: boolean; - /** Step size for zooming in/out on minimap */ + /** + * Step size for zooming in/out on minimap. + * @default 10 + */ zoomStep?: number; - /** Offset the viewport on the minmap, acts like a padding */ + /** + * Offset the viewport on the minimap, acts like a padding. + * @default 5 + */ offsetScale?: number; }; diff --git a/packages/react/src/components/Panel/index.tsx b/packages/react/src/components/Panel/index.tsx index 8d854b91..16fe7841 100644 --- a/packages/react/src/components/Panel/index.tsx +++ b/packages/react/src/components/Panel/index.tsx @@ -1,4 +1,4 @@ -import { forwardRef, type HTMLAttributes, type ReactNode } from 'react'; +import { HTMLAttributes, forwardRef } from 'react'; import cc from 'classcat'; import type { PanelPosition } from '@xyflow/system'; @@ -10,10 +10,10 @@ import type { ReactFlowState } from '../../types'; */ export type PanelProps = HTMLAttributes & { /** - * The position of the panel + * The position of the panel. + * @default "top-left" */ position?: PanelPosition; - children: ReactNode; }; const selector = (s: ReactFlowState) => (s.userSelectionActive ? 'none' : 'all'); From 06cf4c10f5d8a43f57ee0fde19d9a3fe1044cf48 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:04:42 +0200 Subject: [PATCH 116/157] fix: improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` --- .changeset/twenty-cobras-teach.md | 5 +++++ packages/react/src/types/edges.ts | 24 ++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 .changeset/twenty-cobras-teach.md diff --git a/.changeset/twenty-cobras-teach.md b/.changeset/twenty-cobras-teach.md new file mode 100644 index 00000000..e89ef200 --- /dev/null +++ b/.changeset/twenty-cobras-teach.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +dd diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 8fddf865..9d601037 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -50,6 +50,11 @@ export type Edge< EdgeLabelOptions & { style?: CSSProperties; className?: string; + /** + * Determines whether the edge can be updated by dragging the source or target to a new node. + * This property will override the default set by the `edgesReconnectable` prop on the + * `` component. + */ reconnectable?: boolean | HandleType; focusable?: boolean; }; @@ -109,15 +114,11 @@ export type EdgeWrapperProps = { */ export type DefaultEdgeOptions = DefaultEdgeOptionsBase; -export type EdgeTextProps = SVGAttributes & +export type EdgeTextProps = Omit, 'x' | 'y'> & EdgeLabelOptions & { - /** - * The x position where the label should be rendered. - */ + /** The x position where the label should be rendered. */ x: number; - /** - * The y position where the label should be rendered. - */ + /** The y position where the label should be rendered. */ y: number; }; @@ -147,11 +148,12 @@ export type EdgeProps = Pick< * @public * @expand */ -export type BaseEdgeProps = Omit, 'd'> & +export type BaseEdgeProps = Omit, 'd' | 'path'> & EdgeLabelOptions & { /** * The width of the invisible area around the edge that the user can interact with. This is * useful for making the edge easier to click or hover over. + * @default 20 */ interactionWidth?: number; /** The x position of edge label */ @@ -233,7 +235,9 @@ export type OnReconnect = (oldEdge: EdgeType, newC export type ConnectionLineComponentProps = { connectionLineStyle?: CSSProperties; connectionLineType: ConnectionLineType; + /** The node the connection line originates from. */ fromNode: InternalNode; + /** The handle on the `fromNode` that the connection line originates from. */ fromHandle: Handle; fromX: number; fromY: number; @@ -241,6 +245,10 @@ export type ConnectionLineComponentProps = { toY: number; fromPosition: Position; toPosition: Position; + /** + * If there is an `isValidConnection` callback, this prop will be set to `"valid"` or `"invalid"` + * based on the return value of that callback. Otherwise, it will be `null`. + */ connectionStatus: 'valid' | 'invalid' | null; toNode: InternalNode | null; toHandle: Handle | null; From e95f8db11d261fbe0e520c16146fc7d2db6a4ab3 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:05:45 +0200 Subject: [PATCH 117/157] Update .changeset/twenty-cobras-teach.md --- .changeset/twenty-cobras-teach.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/twenty-cobras-teach.md b/.changeset/twenty-cobras-teach.md index e89ef200..4f923bc6 100644 --- a/.changeset/twenty-cobras-teach.md +++ b/.changeset/twenty-cobras-teach.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -dd +fix: improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` From 9c78c2c758abc5fa92461ce9dda099fbcf69cdec Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:10:58 +0200 Subject: [PATCH 118/157] fix: improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` --- packages/system/src/types/handles.ts | 32 ++++++++++++++++------- packages/system/src/types/nodes.ts | 38 ++++++++++++++++++---------- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/packages/system/src/types/handles.ts b/packages/system/src/types/handles.ts index ef67d373..a8b51aa3 100644 --- a/packages/system/src/types/handles.ts +++ b/packages/system/src/types/handles.ts @@ -15,29 +15,43 @@ export type Handle = { export type HandleProps = { /** - * Type of the handle + * Type of the handle. + * @default "source" * @example HandleType.Source, HandleType.Target */ type: HandleType; /** - * Position of the handle - * @example Position.TopLeft, Position.TopRight, - * Position.BottomLeft, Position.BottomRight + * The position of the handle relative to the node. In a horizontal flow source handles are + * typically `Position.Right` and in a vertical flow they are typically `Position.Top`. + * @default Position.Top + * @example Position.TopLeft, Position.TopRight, Position.BottomLeft, Position.BottomRight */ position: Position; - /** Should you be able to connect to/from this handle */ + /** + * Should you be able to connect to/from this handle. + * @default true + */ isConnectable?: boolean; - /** Should you be able to connect from this handle */ + /** + * Dictates whether a connection can start from this handle. + * @default true + */ isConnectableStart?: boolean; - /** Should you be able to connect to this handle */ + /** + * Dictates whether a connection can end on this handle. + * @default true + */ isConnectableEnd?: boolean; /** - * Callback if connection is valid + * Called when a connection is dragged to this handle. You can use this callback to perform some + * custom validation logic based on the connection target and source, for example. Where possible, + * we recommend you move this logic to the `isValidConnection` prop on the main ReactFlow + * component for performance reasons. * @remarks connection becomes an edge if isValidConnection returns true */ isValidConnection?: IsValidConnection; /** - * Id of the handle + * Id of the handle. * @remarks optional if there is only one handle of this type */ id?: string | null; diff --git a/packages/system/src/types/nodes.ts b/packages/system/src/types/nodes.ts index 68dd0ce3..b32d58c5 100644 --- a/packages/system/src/types/nodes.ts +++ b/packages/system/src/types/nodes.ts @@ -12,52 +12,62 @@ export type NodeBase< NodeData extends Record = Record, NodeType extends string = string > = { - /** Unique id of a node */ + /** Unique id of a node. */ id: string; /** - * Position of a node on the pane + * Position of a node on the pane. * @example { x: 0, y: 0 } */ position: XYPosition; - /** Arbitrary data passed to a node */ + /** Arbitrary data passed to a node. */ data: NodeData; - /** Type of node defined in nodeTypes */ + /** Type of node defined in `nodeTypes`. */ type?: NodeType; /** - * Only relevant for default, source, target nodeType. controls source position + * Only relevant for default, source, target nodeType. Controls source position. * @example 'right', 'left', 'top', 'bottom' */ sourcePosition?: Position; /** - * Only relevant for default, source, target nodeType. controls target position + * Only relevant for default, source, target nodeType. Controls target position. * @example 'right', 'left', 'top', 'bottom' */ targetPosition?: Position; + /** Whether or not the node should be visible on the canvas. */ hidden?: boolean; selected?: boolean; - /** True, if node is being dragged */ + /** Whether or not the node is currently being dragged. */ dragging?: boolean; + /** Whether or not the node is able to be dragged. */ draggable?: boolean; selectable?: boolean; connectable?: boolean; deletable?: boolean; + /** + * A class name that can be applied to elements inside the node that allows those elements to act + * as drag handles, letting the user drag the node by clicking and dragging on those elements. + */ dragHandle?: string; width?: number; height?: number; initialWidth?: number; initialHeight?: number; - /** Parent node id, used for creating sub-flows */ + /** Parent node id, used for creating sub-flows. */ parentId?: string; zIndex?: number; /** - * Boundary a node can be moved in + * Boundary a node can be moved in. * @example 'parent' or [[0, 0], [100, 100]] */ extent?: 'parent' | CoordinateExtent; + /** + * When `true`, the parent node will automatically expand if this node is dragged to the edge of + * the parent node's bounds. + */ expandParent?: boolean; ariaLabel?: string; /** - * Origin of the node relative to it's position + * Origin of the node relative to its position. * @example * [0.5, 0.5] // centers the node * [0, 0] // top left @@ -71,7 +81,7 @@ export type NodeBase< }; }; -export type InternalNodeBase = NodeType & { +export type InternalNodeBase = Omit & { measured: { width?: number; height?: number; @@ -99,11 +109,11 @@ export type NodeProps = Pick< 'id' | 'data' | 'width' | 'height' | 'sourcePosition' | 'targetPosition' | 'dragHandle' | 'parentId' > & Required> & { - /** whether a node is connectable or not */ + /** Whether a node is connectable or not. */ isConnectable: boolean; - /** position absolute x value */ + /** Position absolute x value. */ positionAbsoluteX: number; - /** position absolute x value */ + /** Position absolute y value. */ positionAbsoluteY: number; }; From 24a1bc89348817ed9b5c87f74bf2519c705143be Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:11:17 +0200 Subject: [PATCH 119/157] changeset --- .changeset/hungry-coins-sparkle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/hungry-coins-sparkle.md diff --git a/.changeset/hungry-coins-sparkle.md b/.changeset/hungry-coins-sparkle.md new file mode 100644 index 00000000..a60ead63 --- /dev/null +++ b/.changeset/hungry-coins-sparkle.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +fix: improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` From b1e1cc1125d106cf1521a1524286404483e38f30 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:15:05 +0200 Subject: [PATCH 120/157] fix: improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` --- .changeset/light-cherries-greet.md | 5 +++++ packages/react/src/types/instance.ts | 31 +++++++++++++++++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 .changeset/light-cherries-greet.md diff --git a/.changeset/light-cherries-greet.md b/.changeset/light-cherries-greet.md new file mode 100644 index 00000000..299f0555 --- /dev/null +++ b/.changeset/light-cherries-greet.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` diff --git a/packages/react/src/types/instance.ts b/packages/react/src/types/instance.ts index 7aa615f5..d001486a 100644 --- a/packages/react/src/types/instance.ts +++ b/packages/react/src/types/instance.ts @@ -24,13 +24,17 @@ export type GeneralHelpers NodeType[]; /** - * Sets nodes. + * Set your nodes array to something else by either overwriting it with a new array or by passing + * in a function to update the existing array. If using a function, it is important to make sure a + * new array is returned instead of mutating the existing array. Calling this function will + * trigger the `onNodesChange` handler in a controlled flow. * * @param payload - the nodes to set or a function that receives the current nodes and returns the new nodes */ setNodes: (payload: NodeType[] | ((nodes: NodeType[]) => NodeType[])) => void; /** - * Adds nodes. + * Add one or many nodes to your existing nodes array. Calling this function will trigger the + * `onNodesChange` handler in a controlled flow. * * @param payload - the nodes to add */ @@ -56,13 +60,17 @@ export type GeneralHelpers EdgeType[]; /** - * Sets edges. + * Set your edges array to something else by either overwriting it with a new array or by passing + * in a function to update the existing array. If using a function, it is important to make sure a + * new array is returned instead of mutating the existing array. Calling this function will + * trigger the `onEdgesChange` handler in a controlled flow. * * @param payload - the edges to set or a function that receives the current edges and returns the new edges */ setEdges: (payload: EdgeType[] | ((edges: EdgeType[]) => EdgeType[])) => void; /** - * Adds edges. + * Add one or many edges to your existing edges array. Calling this function will trigger the + * `onEdgesChange` handler in a controlled flow. * * @param payload - the edges to add */ @@ -93,7 +101,8 @@ export type GeneralHelpers; /** - * Returns all nodes that intersect with the given node or rect. + * Find all the nodes currently intersecting with a given node or rectangle. The `partially` + * parameter can be set to `true` to include nodes that are only partially intersecting. * * @param node - the node or rect to check for intersections * @param partially - if true, the node is considered to be intersecting if it partially overlaps with the passed node or rect @@ -107,7 +116,8 @@ export type GeneralHelpers NodeType[]; /** - * Checks if the given node or rect intersects with the passed rect. + * Determine if a given node or rectangle is intersecting with another rectangle. The `partially` + * parameter can be set to true return `true` even if the node is only partially intersecting. * * @param node - the node or rect to check for intersections * @param area - the rect to check for intersections @@ -185,7 +195,8 @@ export type GeneralHelpers Rect; /** - * Gets all connections for a given handle belonging to a specific node. + * Get all the connections of a handle belonging to a specific node. The type parameter be either + * `'source'` or `'target'`. * @deprecated * @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) @@ -241,6 +252,10 @@ export type ReactFlowInstance & - Omit & { + ViewportHelperFunctions & { + /** + * React Flow needs to mount the viewport to the DOM and initialize its zoom and pan behavior. + * This property tells you when viewport is initialized. + */ viewportInitialized: boolean; }; From 5a1ce56e8ce83f01e01ef531d90c52181c3e3a1a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 1 Apr 2025 21:17:16 +0200 Subject: [PATCH 121/157] fix: compare `nodeStrokeWidth` with `number`, not with `string` --- .changeset/rotten-news-deliver.md | 5 +++++ packages/react/src/additional-components/MiniMap/MiniMap.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/rotten-news-deliver.md diff --git a/.changeset/rotten-news-deliver.md b/.changeset/rotten-news-deliver.md new file mode 100644 index 00000000..a44721e1 --- /dev/null +++ b/.changeset/rotten-news-deliver.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +fix: compare `nodeStrokeWidth` with `number`, not with `string` diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index ad899043..dfb018b8 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -143,7 +143,7 @@ function MiniMapComponent({ typeof maskStrokeWidth === 'number' ? maskStrokeWidth * viewScale : undefined, '--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined, '--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined, - '--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined, + '--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'number' ? nodeStrokeWidth : undefined, } as CSSProperties } className={cc(['react-flow__minimap', className])} From 5c66916370dc66f2e42c8488e37a7bc2b95cf9f3 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 13:41:08 +0200 Subject: [PATCH 122/157] fix(minimap): return usernode --- packages/react/src/additional-components/MiniMap/MiniMap.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/additional-components/MiniMap/MiniMap.tsx b/packages/react/src/additional-components/MiniMap/MiniMap.tsx index ad899043..bad28242 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMap.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMap.tsx @@ -125,7 +125,7 @@ function MiniMapComponent({ const onSvgNodeClick = onNodeClick ? useCallback((event: MouseEvent, nodeId: string) => { - const node = store.getState().nodeLookup.get(nodeId)!; + const node: NodeType = store.getState().nodeLookup.get(nodeId)!.internals.userNode; onNodeClick(event, node); }, []) : undefined; From 0f293eebae4019a0501a9747ba5dea61a8a413fc Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 13:53:32 +0200 Subject: [PATCH 123/157] fix(minimap): return usernode --- .../src/additional-components/MiniMap/MiniMapNodes.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx b/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx index 2c314289..e96dd9f6 100644 --- a/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx +++ b/packages/react/src/additional-components/MiniMap/MiniMapNodes.tsx @@ -6,7 +6,7 @@ import { shallow } from 'zustand/shallow'; import { useStore } from '../../hooks/useStore'; import { MiniMapNode } from './MiniMapNode'; -import type { ReactFlowState, Node, InternalNode } from '../../types'; +import type { ReactFlowState, Node } from '../../types'; import type { MiniMapNodes as MiniMapNodesProps, GetMiniMapNodeAttribute, MiniMapNodeProps } from './types'; declare const window: any; @@ -42,7 +42,7 @@ function MiniMapNodes({ * The split of responsibilities between MiniMapNodes and * NodeComponentWrapper may appear weird. However, it’s designed to * minimize the cost of updates when individual nodes change. - * + * * For more details, see a similar commit in `NodeRenderer/index.tsx`. */ @@ -84,8 +84,9 @@ function NodeComponentWrapperInner({ shapeRendering: string; }) { const { node, x, y, width, height } = useStore((s) => { - const node = s.nodeLookup.get(id) as InternalNode; - const { x, y } = node.internals.positionAbsolute; + const { internals } = s.nodeLookup.get(id)!; + const node = internals.userNode as NodeType; + const { x, y } = internals.positionAbsolute; const { width, height } = getNodeDimensions(node); return { From cc64a1902a73ad850ee88b2082d6b4509ccba5ec Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 19:45:15 +0200 Subject: [PATCH 124/157] refactor(node-resizer): pass latest dimensions to onEnd handler #5083 --- .../additional-components/NodeResizer/NodeResizeControl.tsx | 6 +++++- packages/system/src/xyresizer/XYResizer.ts | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx index 5be4eafd..0748ffa6 100644 --- a/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx +++ b/packages/react/src/additional-components/NodeResizer/NodeResizeControl.tsx @@ -142,11 +142,15 @@ function ResizeControl({ triggerNodeChanges(changes); }, - onEnd: () => { + onEnd: ({ width, height }) => { const dimensionChange: NodeDimensionChange = { id: id, type: 'dimensions', resizing: false, + dimensions: { + width, + height, + }, }; store.getState().triggerNodeChanges([dimensionChange]); }, diff --git a/packages/system/src/xyresizer/XYResizer.ts b/packages/system/src/xyresizer/XYResizer.ts index 44dd1ac6..f4cd150b 100644 --- a/packages/system/src/xyresizer/XYResizer.ts +++ b/packages/system/src/xyresizer/XYResizer.ts @@ -48,7 +48,7 @@ type XYResizerParams = { paneDomNode: HTMLDivElement | null; }; onChange: (changes: XYResizerChange, childChanges: XYResizerChildChange[]) => void; - onEnd?: () => void; + onEnd?: (change: Required) => void; }; type XYResizerUpdateParams = { @@ -188,13 +188,13 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X }) .on('drag', (event: ResizeDragEvent) => { const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems(); - const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid, containerBounds, }); + const childChanges: XYResizerChildChange[] = []; if (!node) { @@ -294,7 +294,7 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }: X }) .on('end', (event: ResizeDragEvent) => { onResizeEnd?.(event, { ...prevValues }); - onEnd?.(); + onEnd?.({ ...prevValues }); }); selection.call(dragHandler); } From f819005be362d044b16ce4c0b85432f3f300a13a Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 19:47:21 +0200 Subject: [PATCH 125/157] chore(changeset): add --- .changeset/happy-pots-sell.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/happy-pots-sell.md diff --git a/.changeset/happy-pots-sell.md b/.changeset/happy-pots-sell.md new file mode 100644 index 00000000..15f9ff04 --- /dev/null +++ b/.changeset/happy-pots-sell.md @@ -0,0 +1,6 @@ +--- +'@xyflow/react': patch +'@xyflow/system': patch +--- + +Pass dimensions to final resize change event From 9980cff2fe0a6c7a0cd1791622987660813ea99c Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 20:46:08 +0200 Subject: [PATCH 126/157] chore(xypanzoom): prevent default for pinch zoom on nowheel element #5074 --- packages/system/src/xypanzoom/eventhandler.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/system/src/xypanzoom/eventhandler.ts b/packages/system/src/xypanzoom/eventhandler.ts index 751a31c5..78fd9253 100644 --- a/packages/system/src/xypanzoom/eventhandler.ts +++ b/packages/system/src/xypanzoom/eventhandler.ts @@ -141,11 +141,20 @@ export function createPanOnScrollHandler({ export function createZoomOnScrollHandler({ noWheelClassName, preventScrolling, d3ZoomHandler }: ZoomOnScrollParams) { return function (this: Element, event: any, d: unknown) { - // we still want to enable pinch zooming even if preventScrolling is set to false - const preventZoom = !preventScrolling && event.type === 'wheel' && !event.ctrlKey; + if (event.type === 'wheel') { + const isPinch = event.ctrlKey; + // we still want to enable pinch zooming even if preventScrolling is set to false + const preventZoom = !preventScrolling && !isPinch; + const isNoWheel = isWrappedWithClass(event, noWheelClassName); - if (preventZoom || isWrappedWithClass(event, noWheelClassName)) { - return null; + // if user is pinch zooming above a nowheel element, we don't want the browser to zoom + if (isPinch && isNoWheel) { + event.preventDefault(); + } + + if (preventZoom || isNoWheel) { + return null; + } } event.preventDefault(); From 2ac6e155e35256ca436281df16344366e7d05761 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 20:46:53 +0200 Subject: [PATCH 127/157] chore(changeset): add --- .changeset/sweet-chicken-lie.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sweet-chicken-lie.md diff --git a/.changeset/sweet-chicken-lie.md b/.changeset/sweet-chicken-lie.md new file mode 100644 index 00000000..eccb0db0 --- /dev/null +++ b/.changeset/sweet-chicken-lie.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Prevent browser zoom for pinch zoom gestures on nowheel elements From 77701143ca405984d4171fc479829ed4fc52f04b Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 20:49:37 +0200 Subject: [PATCH 128/157] chore(xypanzoom): cleanup --- packages/system/src/xypanzoom/eventhandler.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/system/src/xypanzoom/eventhandler.ts b/packages/system/src/xypanzoom/eventhandler.ts index 78fd9253..e6dda425 100644 --- a/packages/system/src/xypanzoom/eventhandler.ts +++ b/packages/system/src/xypanzoom/eventhandler.ts @@ -141,20 +141,18 @@ export function createPanOnScrollHandler({ export function createZoomOnScrollHandler({ noWheelClassName, preventScrolling, d3ZoomHandler }: ZoomOnScrollParams) { return function (this: Element, event: any, d: unknown) { - if (event.type === 'wheel') { - const isPinch = event.ctrlKey; - // we still want to enable pinch zooming even if preventScrolling is set to false - const preventZoom = !preventScrolling && !isPinch; - const isNoWheel = isWrappedWithClass(event, noWheelClassName); + const isWheel = event.type === 'wheel'; + // we still want to enable pinch zooming even if preventScrolling is set to false + const preventZoom = !preventScrolling && isWheel && !event.ctrlKey; + const hasNoWheelClass = isWrappedWithClass(event, noWheelClassName); - // if user is pinch zooming above a nowheel element, we don't want the browser to zoom - if (isPinch && isNoWheel) { - event.preventDefault(); - } + // if user is pinch zooming above a nowheel element, we don't want the browser to zoom + if (event.ctrlKey && isWheel && hasNoWheelClass) { + event.preventDefault(); + } - if (preventZoom || isNoWheel) { - return null; - } + if (preventZoom || hasNoWheelClass) { + return null; } event.preventDefault(); From 5689723e47a3f839d8bbbd358b2190e5b2fb2c9f Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 2 Apr 2025 20:55:04 +0200 Subject: [PATCH 129/157] chore(changesets): cleanup --- .changeset/eleven-spoons-attend.md | 2 +- .changeset/flat-taxis-provide.md | 2 +- .changeset/grumpy-toes-sniff.md | 2 +- .changeset/hungry-coins-sparkle.md | 2 +- .changeset/itchy-terms-carry.md | 2 +- .changeset/light-cherries-greet.md | 2 +- .changeset/pink-toes-care.md | 2 +- .changeset/rotten-news-deliver.md | 2 +- .changeset/silly-buckets-relate.md | 2 +- .changeset/tall-knives-wink.md | 2 +- .changeset/twenty-cobras-teach.md | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.changeset/eleven-spoons-attend.md b/.changeset/eleven-spoons-attend.md index d18ccf0c..ebf9ecf6 100644 --- a/.changeset/eleven-spoons-attend.md +++ b/.changeset/eleven-spoons-attend.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix `@default` TSDoc tags for `BackgroundProps` +Adjust `@default` TSDoc tags for `BackgroundProps` diff --git a/.changeset/flat-taxis-provide.md b/.changeset/flat-taxis-provide.md index d9856d36..84f8e004 100644 --- a/.changeset/flat-taxis-provide.md +++ b/.changeset/flat-taxis-provide.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` +Improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` diff --git a/.changeset/grumpy-toes-sniff.md b/.changeset/grumpy-toes-sniff.md index 70cb871d..fb06622e 100644 --- a/.changeset/grumpy-toes-sniff.md +++ b/.changeset/grumpy-toes-sniff.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: improve TSDoc comments for `MiniMapProps` and `PanelProps` +Improve TSDoc comments for `MiniMapProps` and `PanelProps` diff --git a/.changeset/hungry-coins-sparkle.md b/.changeset/hungry-coins-sparkle.md index a60ead63..f20c46ea 100644 --- a/.changeset/hungry-coins-sparkle.md +++ b/.changeset/hungry-coins-sparkle.md @@ -2,4 +2,4 @@ '@xyflow/system': patch --- -fix: improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` +Improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` diff --git a/.changeset/itchy-terms-carry.md b/.changeset/itchy-terms-carry.md index f7760c4d..e8d6917b 100644 --- a/.changeset/itchy-terms-carry.md +++ b/.changeset/itchy-terms-carry.md @@ -2,4 +2,4 @@ '@xyflow/system': patch --- -fix: improve TSDoc comments for `EdgeBase` +Improve TSDoc comments for `EdgeBase` diff --git a/.changeset/light-cherries-greet.md b/.changeset/light-cherries-greet.md index 299f0555..1f59d8c2 100644 --- a/.changeset/light-cherries-greet.md +++ b/.changeset/light-cherries-greet.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` +Improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` diff --git a/.changeset/pink-toes-care.md b/.changeset/pink-toes-care.md index 67f016a0..7983bf22 100644 --- a/.changeset/pink-toes-care.md +++ b/.changeset/pink-toes-care.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` +Improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` diff --git a/.changeset/rotten-news-deliver.md b/.changeset/rotten-news-deliver.md index a44721e1..33b61d1f 100644 --- a/.changeset/rotten-news-deliver.md +++ b/.changeset/rotten-news-deliver.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: compare `nodeStrokeWidth` with `number`, not with `string` +Compare `nodeStrokeWidth` with `number`, not with `string` within `MiniMap` diff --git a/.changeset/silly-buckets-relate.md b/.changeset/silly-buckets-relate.md index 99e6bc91..7b8b0e0b 100644 --- a/.changeset/silly-buckets-relate.md +++ b/.changeset/silly-buckets-relate.md @@ -3,4 +3,4 @@ '@xyflow/system': patch --- -fix: use `rgba` for colors with opacity instead of `rgb` +Use `rgba` for colors with opacity instead of `rgb` for `MiniMap` mask color diff --git a/.changeset/tall-knives-wink.md b/.changeset/tall-knives-wink.md index c6b2f9b3..1bc3a520 100644 --- a/.changeset/tall-knives-wink.md +++ b/.changeset/tall-knives-wink.md @@ -2,4 +2,4 @@ '@xyflow/system': patch --- -fix: improve TSDoc comments for `Connection` and `ConnectionInProgress` +Improve TSDoc comments for `Connection` and `ConnectionInProgress` diff --git a/.changeset/twenty-cobras-teach.md b/.changeset/twenty-cobras-teach.md index 4f923bc6..3518d41e 100644 --- a/.changeset/twenty-cobras-teach.md +++ b/.changeset/twenty-cobras-teach.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -fix: improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` +Improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` From 9a4011aa2b965ce30097dcd1d672b7b6edc271ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 2 Apr 2025 18:56:21 +0000 Subject: [PATCH 130/157] chore(packages): bump --- .changeset/eleven-spoons-attend.md | 5 ----- .changeset/flat-taxis-provide.md | 5 ----- .changeset/grumpy-toes-sniff.md | 5 ----- .changeset/happy-pots-sell.md | 6 ------ .changeset/hungry-coins-sparkle.md | 5 ----- .changeset/itchy-terms-carry.md | 5 ----- .changeset/light-cherries-greet.md | 5 ----- .changeset/pink-toes-care.md | 5 ----- .changeset/rotten-news-deliver.md | 5 ----- .changeset/silly-buckets-relate.md | 6 ------ .changeset/sweet-chicken-lie.md | 5 ----- .changeset/tall-knives-wink.md | 5 ----- .changeset/twenty-cobras-teach.md | 5 ----- packages/react/CHANGELOG.md | 23 +++++++++++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 9 +++++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 16 ++++++++++++++++ packages/system/package.json | 2 +- 19 files changed, 51 insertions(+), 70 deletions(-) delete mode 100644 .changeset/eleven-spoons-attend.md delete mode 100644 .changeset/flat-taxis-provide.md delete mode 100644 .changeset/grumpy-toes-sniff.md delete mode 100644 .changeset/happy-pots-sell.md delete mode 100644 .changeset/hungry-coins-sparkle.md delete mode 100644 .changeset/itchy-terms-carry.md delete mode 100644 .changeset/light-cherries-greet.md delete mode 100644 .changeset/pink-toes-care.md delete mode 100644 .changeset/rotten-news-deliver.md delete mode 100644 .changeset/silly-buckets-relate.md delete mode 100644 .changeset/sweet-chicken-lie.md delete mode 100644 .changeset/tall-knives-wink.md delete mode 100644 .changeset/twenty-cobras-teach.md diff --git a/.changeset/eleven-spoons-attend.md b/.changeset/eleven-spoons-attend.md deleted file mode 100644 index ebf9ecf6..00000000 --- a/.changeset/eleven-spoons-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Adjust `@default` TSDoc tags for `BackgroundProps` diff --git a/.changeset/flat-taxis-provide.md b/.changeset/flat-taxis-provide.md deleted file mode 100644 index 84f8e004..00000000 --- a/.changeset/flat-taxis-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` diff --git a/.changeset/grumpy-toes-sniff.md b/.changeset/grumpy-toes-sniff.md deleted file mode 100644 index fb06622e..00000000 --- a/.changeset/grumpy-toes-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `MiniMapProps` and `PanelProps` diff --git a/.changeset/happy-pots-sell.md b/.changeset/happy-pots-sell.md deleted file mode 100644 index 15f9ff04..00000000 --- a/.changeset/happy-pots-sell.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/system': patch ---- - -Pass dimensions to final resize change event diff --git a/.changeset/hungry-coins-sparkle.md b/.changeset/hungry-coins-sparkle.md deleted file mode 100644 index f20c46ea..00000000 --- a/.changeset/hungry-coins-sparkle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` diff --git a/.changeset/itchy-terms-carry.md b/.changeset/itchy-terms-carry.md deleted file mode 100644 index e8d6917b..00000000 --- a/.changeset/itchy-terms-carry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `EdgeBase` diff --git a/.changeset/light-cherries-greet.md b/.changeset/light-cherries-greet.md deleted file mode 100644 index 1f59d8c2..00000000 --- a/.changeset/light-cherries-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` diff --git a/.changeset/pink-toes-care.md b/.changeset/pink-toes-care.md deleted file mode 100644 index 7983bf22..00000000 --- a/.changeset/pink-toes-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` diff --git a/.changeset/rotten-news-deliver.md b/.changeset/rotten-news-deliver.md deleted file mode 100644 index 33b61d1f..00000000 --- a/.changeset/rotten-news-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Compare `nodeStrokeWidth` with `number`, not with `string` within `MiniMap` diff --git a/.changeset/silly-buckets-relate.md b/.changeset/silly-buckets-relate.md deleted file mode 100644 index 7b8b0e0b..00000000 --- a/.changeset/silly-buckets-relate.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/svelte': patch -'@xyflow/system': patch ---- - -Use `rgba` for colors with opacity instead of `rgb` for `MiniMap` mask color diff --git a/.changeset/sweet-chicken-lie.md b/.changeset/sweet-chicken-lie.md deleted file mode 100644 index eccb0db0..00000000 --- a/.changeset/sweet-chicken-lie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Prevent browser zoom for pinch zoom gestures on nowheel elements diff --git a/.changeset/tall-knives-wink.md b/.changeset/tall-knives-wink.md deleted file mode 100644 index 1bc3a520..00000000 --- a/.changeset/tall-knives-wink.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `Connection` and `ConnectionInProgress` diff --git a/.changeset/twenty-cobras-teach.md b/.changeset/twenty-cobras-teach.md deleted file mode 100644 index 3518d41e..00000000 --- a/.changeset/twenty-cobras-teach.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 7c4ba5db..e875040d 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,28 @@ # @xyflow/react +## 12.5.4 + +### Patch Changes + +- [#5134](https://github.com/xyflow/xyflow/pull/5134) [`7acab1e1`](https://github.com/xyflow/xyflow/commit/7acab1e123944c296180fbf826a3fd488963608f) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Adjust `@default` TSDoc tags for `BackgroundProps` + +- [#5135](https://github.com/xyflow/xyflow/pull/5135) [`754a1671`](https://github.com/xyflow/xyflow/commit/754a167134f22fa00a139de4c7e10aaaa1953ac8) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `NodeResizerProps` and `ResizeControlProps` + +- [#5140](https://github.com/xyflow/xyflow/pull/5140) [`82e6860e`](https://github.com/xyflow/xyflow/commit/82e6860e1354b8bb8047399b7773fd090be206d7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `MiniMapProps` and `PanelProps` + +- [#5147](https://github.com/xyflow/xyflow/pull/5147) [`f819005b`](https://github.com/xyflow/xyflow/commit/f819005be362d044b16ce4c0b85432f3f300a13a) Thanks [@moklick](https://github.com/moklick)! - Pass dimensions to final resize change event + +- [#5143](https://github.com/xyflow/xyflow/pull/5143) [`b1e1cc11`](https://github.com/xyflow/xyflow/commit/b1e1cc1125d106cf1521a1524286404483e38f30) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `ReactFlowInstance` and `GeneralHelpers` + +- [#5138](https://github.com/xyflow/xyflow/pull/5138) [`d4eb8d52`](https://github.com/xyflow/xyflow/commit/d4eb8d52d0e26e9534ec5fc347211ce91d1ddd32) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `ViewportHelperFunctions` and `NodeToolbarProps` + +- [#5144](https://github.com/xyflow/xyflow/pull/5144) [`5a1ce56e`](https://github.com/xyflow/xyflow/commit/5a1ce56e8ce83f01e01ef531d90c52181c3e3a1a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Compare `nodeStrokeWidth` with `number`, not with `string` within `MiniMap` + +- [#5141](https://github.com/xyflow/xyflow/pull/5141) [`06cf4c10`](https://github.com/xyflow/xyflow/commit/06cf4c10f5d8a43f57ee0fde19d9a3fe1044cf48) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `Edge`, `BaseEdgeProps` and `ConnectionLineComponentProps` + +- Updated dependencies [[`f819005b`](https://github.com/xyflow/xyflow/commit/f819005be362d044b16ce4c0b85432f3f300a13a), [`24a1bc89`](https://github.com/xyflow/xyflow/commit/24a1bc89348817ed9b5c87f74bf2519c705143be), [`36657cd6`](https://github.com/xyflow/xyflow/commit/36657cd66322c911e87eb37275c584a80025adfe), [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654), [`2ac6e155`](https://github.com/xyflow/xyflow/commit/2ac6e155e35256ca436281df16344366e7d05761), [`f0f378e5`](https://github.com/xyflow/xyflow/commit/f0f378e5b6918c2c30d9dc1e32587063cb942d4e)]: + - @xyflow/system@0.0.54 + ## 12.5.3 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 8057a940..0cd5389d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.3", + "version": "12.5.4", "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 926d6bb7..82b45d97 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,14 @@ # @xyflow/svelte +## 0.1.34 + +### Patch Changes + +- [#5139](https://github.com/xyflow/xyflow/pull/5139) [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Use `rgba` for colors with opacity instead of `rgb` for `MiniMap` mask color + +- Updated dependencies [[`f819005b`](https://github.com/xyflow/xyflow/commit/f819005be362d044b16ce4c0b85432f3f300a13a), [`24a1bc89`](https://github.com/xyflow/xyflow/commit/24a1bc89348817ed9b5c87f74bf2519c705143be), [`36657cd6`](https://github.com/xyflow/xyflow/commit/36657cd66322c911e87eb37275c584a80025adfe), [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654), [`2ac6e155`](https://github.com/xyflow/xyflow/commit/2ac6e155e35256ca436281df16344366e7d05761), [`f0f378e5`](https://github.com/xyflow/xyflow/commit/f0f378e5b6918c2c30d9dc1e32587063cb942d4e)]: + - @xyflow/system@0.0.54 + ## 0.1.33 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 7fe3b7da..e76df3d1 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.33", + "version": "0.1.34", "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 0c193291..4db8b580 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,21 @@ # @xyflow/system +## 0.0.54 + +### Patch Changes + +- [#5147](https://github.com/xyflow/xyflow/pull/5147) [`f819005b`](https://github.com/xyflow/xyflow/commit/f819005be362d044b16ce4c0b85432f3f300a13a) Thanks [@moklick](https://github.com/moklick)! - Pass dimensions to final resize change event + +- [#5142](https://github.com/xyflow/xyflow/pull/5142) [`24a1bc89`](https://github.com/xyflow/xyflow/commit/24a1bc89348817ed9b5c87f74bf2519c705143be) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `HandleProps`, `NodeBase` and `InternalNodeBase` + +- [#5136](https://github.com/xyflow/xyflow/pull/5136) [`36657cd6`](https://github.com/xyflow/xyflow/commit/36657cd66322c911e87eb37275c584a80025adfe) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `EdgeBase` + +- [#5139](https://github.com/xyflow/xyflow/pull/5139) [`89de9ca8`](https://github.com/xyflow/xyflow/commit/89de9ca83fbf9263a687a0f5f915efb2beb31654) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Use `rgba` for colors with opacity instead of `rgb` for `MiniMap` mask color + +- [#5148](https://github.com/xyflow/xyflow/pull/5148) [`2ac6e155`](https://github.com/xyflow/xyflow/commit/2ac6e155e35256ca436281df16344366e7d05761) Thanks [@moklick](https://github.com/moklick)! - Prevent browser zoom for pinch zoom gestures on nowheel elements + +- [#5137](https://github.com/xyflow/xyflow/pull/5137) [`f0f378e5`](https://github.com/xyflow/xyflow/commit/f0f378e5b6918c2c30d9dc1e32587063cb942d4e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `Connection` and `ConnectionInProgress` + ## 0.0.53 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index ed8f3c06..f91937a6 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.53", + "version": "0.0.54", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", From 4ef93d611fc82b0d6b289ded79da9018b213b7cd Mon Sep 17 00:00:00 2001 From: Ilia <43846662+ibagov@users.noreply.github.com> Date: Sat, 5 Apr 2025 14:35:35 +0200 Subject: [PATCH 131/157] Update onNodesChange docstring in component-props.ts Removed all references of edges in the docstring of onNodesChange --- packages/react/src/types/component-props.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index d558bc47..630fc4f3 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -137,16 +137,16 @@ export interface ReactFlowProps void; /** * This event handler is called when a Node is updated - * @example // Use NodesState hook to create edges and get onNodesChange handler + * @example // Use NodesState hook to create nodes and get onNodesChange handler * import ReactFlow, { useNodesState } from '@xyflow/react'; - * const [edges, setNodes, onNodesChange] = useNodesState(initialNodes); + * const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); * * return () - * @example // Use helper function to update edge + * @example // Use helper function to update node * import ReactFlow, { applyNodeChanges } from '@xyflow/react'; * * const onNodeChange = useCallback( - * (changes) => setNode((eds) => applyNodeChanges(changes, eds)), + * (changes) => setNode((nds) => applyNodeChanges(changes, nds)), * [], * ); * From aaebc462951ded8e91374c3e084d77af5ed7380a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:02:47 +0200 Subject: [PATCH 132/157] Improve TSDoc comments for `type GetStraightPathParams` and `getStraightPath` function --- .changeset/neat-horses-invite.md | 5 +++++ .../system/src/utils/edges/straight-edge.ts | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 .changeset/neat-horses-invite.md diff --git a/.changeset/neat-horses-invite.md b/.changeset/neat-horses-invite.md new file mode 100644 index 00000000..b04e58e3 --- /dev/null +++ b/.changeset/neat-horses-invite.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Improve TSDoc comments for `type GetStraightPathParams` and `getStraightPath` function diff --git a/packages/system/src/utils/edges/straight-edge.ts b/packages/system/src/utils/edges/straight-edge.ts index baa7093b..c5bc3db2 100644 --- a/packages/system/src/utils/edges/straight-edge.ts +++ b/packages/system/src/utils/edges/straight-edge.ts @@ -1,20 +1,29 @@ import { getEdgeCenter } from './general'; export type GetStraightPathParams = { + /** The `x` position of the source handle. */ sourceX: number; + /** The `y` position of the source handle. */ sourceY: number; + /** The `x` position of the target handle. */ targetX: number; + /** The `y` position of the target handle. */ targetY: number; }; /** * Calculates the straight line path between two points. * @public - * @param params.sourceX - The x position of the source handle - * @param params.sourceY - The y position of the source handle - * @param params.targetX - The x position of the target handle - * @param params.targetY - The y position of the target handle - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label + * @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path) + * and `offsetX`, `offsetY` between source handle and label. + * + * - `path`: the path to use in an SVG `` element. + * - `labelX`: the `x` position you can use to render a label for this edge. + * - `labelY`: the `y` position you can use to render a label for this edge. + * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the + * middle of this path. + * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the + * middle of this path. * @example * ```js * const source = { x: 0, y: 20 }; From 02a3b74645799a3f0ce670b69365fa86ecb0616e Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:04:53 +0200 Subject: [PATCH 133/157] Improve TSDoc comments for `type GetSmoothStepPathParams` and `getSmoothStepPath` function --- .changeset/empty-apples-push.md | 5 +++ .../system/src/utils/edges/smoothstep-edge.ts | 36 +++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 .changeset/empty-apples-push.md diff --git a/.changeset/empty-apples-push.md b/.changeset/empty-apples-push.md new file mode 100644 index 00000000..1ed770ee --- /dev/null +++ b/.changeset/empty-apples-push.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Improve TSDoc comments for `type GetSmoothStepPathParams` and `getSmoothStepPath` function diff --git a/packages/system/src/utils/edges/smoothstep-edge.ts b/packages/system/src/utils/edges/smoothstep-edge.ts index 0771f357..3de3fbdc 100644 --- a/packages/system/src/utils/edges/smoothstep-edge.ts +++ b/packages/system/src/utils/edges/smoothstep-edge.ts @@ -2,15 +2,29 @@ import { getEdgeCenter } from './general'; import { Position, type XYPosition } from '../../types'; export interface GetSmoothStepPathParams { + /** The `x` position of the source handle. */ sourceX: number; + /** The `y` position of the source handle. */ sourceY: number; + /** + * The position of the source handle. + * @default Position.Bottom + */ sourcePosition?: Position; + /** The `x` position of the target handle. */ targetX: number; + /** The `y` position of the target handle. */ targetY: number; + /** + * The position of the target handle. + * @default Position.Top + */ targetPosition?: Position; + /** @default 5 */ borderRadius?: number; centerX?: number; centerY?: number; + /** @default 20 */ offset?: number; } @@ -39,8 +53,8 @@ const getDirection = ({ const distance = (a: XYPosition, b: XYPosition) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); /* - * ith this function we try to mimic a orthogonal edge routing behaviour - * It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges + * With this function we try to mimic an orthogonal edge routing behaviour + * It's not as good as a real orthogonal edge routing, but it's faster and good enough as a default for step and smooth step edges */ function getPoints({ source, @@ -198,15 +212,9 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str /** * The `getSmoothStepPath` util returns everything you need to render a stepped path - *between two nodes. The `borderRadius` property can be used to choose how rounded - *the corners of those steps are. + * between two nodes. The `borderRadius` property can be used to choose how rounded + * the corners of those steps are. * @public - * @param params.sourceX - The x position of the source handle - * @param params.sourceY - The y position of the source handle - * @param params.sourcePosition - The position of the source handle (default: Position.Bottom) - * @param params.targetX - The x position of the target handle - * @param params.targetY - The y position of the target handle - * @param params.targetPosition - The position of the target handle (default: Position.Top) * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label * @example * ```js @@ -223,6 +231,14 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str * }); * ``` * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once. + * @returns + * - `path`: the path to use in an SVG `` element. + * - `labelX`: the `x` position you can use to render a label for this edge. + * - `labelY`: the `y` position you can use to render a label for this edge. + * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the + * middle of this path. + * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the + * middle of this path. */ export function getSmoothStepPath({ sourceX, From 6ec942fc6501f81009c278cc995764bef3e8d03b Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:06:50 +0200 Subject: [PATCH 134/157] Improve TSDoc comments for `type GetBezierPathParams` and `getBezierPath` function --- .changeset/rich-mirrors-exist.md | 5 +++ .../system/src/utils/edges/bezier-edge.ts | 33 ++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 .changeset/rich-mirrors-exist.md diff --git a/.changeset/rich-mirrors-exist.md b/.changeset/rich-mirrors-exist.md new file mode 100644 index 00000000..1cff8576 --- /dev/null +++ b/.changeset/rich-mirrors-exist.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Improve TSDoc comments for `type GetBezierPathParams` and `getBezierPath` function diff --git a/packages/system/src/utils/edges/bezier-edge.ts b/packages/system/src/utils/edges/bezier-edge.ts index 3b373938..d5c0b6bb 100644 --- a/packages/system/src/utils/edges/bezier-edge.ts +++ b/packages/system/src/utils/edges/bezier-edge.ts @@ -1,12 +1,28 @@ import { Position } from '../../types'; export type GetBezierPathParams = { + /** The `x` position of the source handle. */ sourceX: number; + /** The `y` position of the source handle. */ sourceY: number; + /** + * The position of the source handle. + * @default Position.Bottom + */ sourcePosition?: Position; + /** The `x` position of the target handle. */ targetX: number; + /** The `y` position of the target handle. */ targetY: number; + /** + * The position of the target handle. + * @default Position.Top + */ targetPosition?: Position; + /** + * The curvature of the bezier edge. + * @default 0.25 + */ curvature?: number; }; @@ -75,14 +91,15 @@ function getControlWithCurvature({ pos, x1, y1, x2, y2, c }: GetControlWithCurva * The `getBezierPath` util returns everything you need to render a bezier edge *between two nodes. * @public - * @param params.sourceX - The x position of the source handle - * @param params.sourceY - The y position of the source handle - * @param params.sourcePosition - The position of the source handle (default: Position.Bottom) - * @param params.targetX - The x position of the target handle - * @param params.targetY - The y position of the target handle - * @param params.targetPosition - The position of the target handle (default: Position.Top) - * @param params.curvature - The curvature of the bezier edge - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label + * @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path) + * and `offsetX`, `offsetY` between source handle and label. + * - `path`: the path to use in an SVG `` element. + * - `labelX`: the `x` position you can use to render a label for this edge. + * - `labelY`: the `y` position you can use to render a label for this edge. + * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the + * middle of this path. + * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the + * middle of this path. * @example * ```js * const source = { x: 0, y: 20 }; From 2a48c3442fa8e45864a66d714f948717a86feea0 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:10:58 +0200 Subject: [PATCH 135/157] remove duplicate @returns tag --- .../system/src/utils/edges/smoothstep-edge.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/system/src/utils/edges/smoothstep-edge.ts b/packages/system/src/utils/edges/smoothstep-edge.ts index 3de3fbdc..b10c5a07 100644 --- a/packages/system/src/utils/edges/smoothstep-edge.ts +++ b/packages/system/src/utils/edges/smoothstep-edge.ts @@ -215,7 +215,16 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str * between two nodes. The `borderRadius` property can be used to choose how rounded * the corners of those steps are. * @public - * @returns A path string you can use in an SVG, the labelX and labelY position (center of path) and offsetX, offsetY between source handle and label + * @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path) + * and `offsetX`, `offsetY` between source handle and label. + * + * - `path`: the path to use in an SVG `` element. + * - `labelX`: the `x` position you can use to render a label for this edge. + * - `labelY`: the `y` position you can use to render a label for this edge. + * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the + * middle of this path. + * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the + * middle of this path. * @example * ```js * const source = { x: 0, y: 20 }; @@ -231,14 +240,6 @@ function getBend(a: XYPosition, b: XYPosition, c: XYPosition, size: number): str * }); * ``` * @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once. - * @returns - * - `path`: the path to use in an SVG `` element. - * - `labelX`: the `x` position you can use to render a label for this edge. - * - `labelY`: the `y` position you can use to render a label for this edge. - * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the - * middle of this path. - * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the - * middle of this path. */ export function getSmoothStepPath({ sourceX, From 0669606050bb2138a44a1591176ac8e16afeb0f1 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:15:42 +0200 Subject: [PATCH 136/157] Fix typo `React Flow` -> `Svelte Flow` --- .changeset/chilly-parrots-rest.md | 5 +++++ packages/svelte/src/lib/types/edges.ts | 4 ++-- packages/svelte/src/lib/utils/index.ts | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 .changeset/chilly-parrots-rest.md diff --git a/.changeset/chilly-parrots-rest.md b/.changeset/chilly-parrots-rest.md new file mode 100644 index 00000000..9801602e --- /dev/null +++ b/.changeset/chilly-parrots-rest.md @@ -0,0 +1,5 @@ +--- +'@xyflow/svelte': patch +--- + +Fix typo `React Flow` -> `Svelte Flow` diff --git a/packages/svelte/src/lib/types/edges.ts b/packages/svelte/src/lib/types/edges.ts index b2f6ba7e..2a9a1445 100644 --- a/packages/svelte/src/lib/types/edges.ts +++ b/packages/svelte/src/lib/types/edges.ts @@ -11,8 +11,8 @@ import type { import type { Node } from '$lib/types'; /** - * An `Edge` is the complete description with everything React Flow needs - *to know in order to render it. + * An `Edge` is the complete description with everything Svelte Flow needs to know in order to + * render it. * @public */ export type Edge< diff --git a/packages/svelte/src/lib/utils/index.ts b/packages/svelte/src/lib/utils/index.ts index 10f205ca..ed1aef35 100644 --- a/packages/svelte/src/lib/utils/index.ts +++ b/packages/svelte/src/lib/utils/index.ts @@ -3,7 +3,7 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '$lib/types'; /** - * Test whether an object is useable as a Node + * Test whether an object is usable as a Node * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true * @param element - The element to test @@ -13,7 +13,7 @@ export const isNode = (element: unknown): element isNodeBase(element); /** - * Test whether an object is useable as an Edge + * Test whether an object is usable as an Edge * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true * @param element - The element to test From 0c1436d6a371240cfa0adecea573c44fd42df7b3 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:18:07 +0200 Subject: [PATCH 137/157] Improve TSDoc comments for `useConnection` hook --- .changeset/five-students-divide.md | 5 +++++ packages/react/src/hooks/useConnection.ts | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 .changeset/five-students-divide.md diff --git a/.changeset/five-students-divide.md b/.changeset/five-students-divide.md new file mode 100644 index 00000000..b4e9e528 --- /dev/null +++ b/.changeset/five-students-divide.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `useConnection` hook diff --git a/packages/react/src/hooks/useConnection.ts b/packages/react/src/hooks/useConnection.ts index 9ed14b67..7c748003 100644 --- a/packages/react/src/hooks/useConnection.ts +++ b/packages/react/src/hooks/useConnection.ts @@ -30,6 +30,10 @@ function getSelector Date: Sat, 5 Apr 2025 17:20:34 +0200 Subject: [PATCH 138/157] Improve TSDoc comments for `type UseHandleConnectionsParams` and `useHandleConnections` hook --- .changeset/many-chefs-clean.md | 5 +++++ packages/react/src/hooks/useHandleConnections.ts | 16 ++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 .changeset/many-chefs-clean.md diff --git a/.changeset/many-chefs-clean.md b/.changeset/many-chefs-clean.md new file mode 100644 index 00000000..85786317 --- /dev/null +++ b/.changeset/many-chefs-clean.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `type UseHandleConnectionsParams` and `useHandleConnections` hook diff --git a/packages/react/src/hooks/useHandleConnections.ts b/packages/react/src/hooks/useHandleConnections.ts index cad87715..a53eb2c7 100644 --- a/packages/react/src/hooks/useHandleConnections.ts +++ b/packages/react/src/hooks/useHandleConnections.ts @@ -10,11 +10,16 @@ import { import { useStore } from './useStore'; import { useNodeId } from '../contexts/NodeIdContext'; -type useHandleConnectionsParams = { +type UseHandleConnectionsParams = { + /** What type of handle connections do you want to observe? */ type: HandleType; + /** The handle id (this is only needed if the node has multiple handles of the same type). */ id?: string | null; + /** If node id is not provided, the node id from the `NodeIdContext` is used. */ nodeId?: string; + /** Gets called when a connection is established. */ onConnect?: (connections: Connection[]) => void; + /** Gets called when a connection is removed. */ onDisconnect?: (connections: Connection[]) => void; }; @@ -23,12 +28,7 @@ type useHandleConnectionsParams = { * * @public * @deprecated Use `useNodeConnections` instead. - * @param param.type - handle type 'source' or 'target' - * @param param.nodeId - node id - if not provided, the node id from the NodeIdContext is used - * @param param.id - the handle id (this is only needed if the node has multiple handles of the same type) - * @param param.onConnect - gets called when a connection is established - * @param param.onDisconnect - gets called when a connection is removed - * @returns an array with handle connections + * @returns An array with handle connections. */ export function useHandleConnections({ type, @@ -36,7 +36,7 @@ export function useHandleConnections({ nodeId, onConnect, onDisconnect, -}: useHandleConnectionsParams): HandleConnection[] { +}: UseHandleConnectionsParams): HandleConnection[] { console.warn( '[DEPRECATED] `useHandleConnections` is deprecated. Instead use `useNodeConnections` https://reactflow.dev/api-reference/hooks/useNodeConnections' ); From c4efe749208e854dc9ced5bdd00933269d5b4382 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:23:12 +0200 Subject: [PATCH 139/157] Improve TSDoc comments for `type UseKeyPressOptions` and `useKeyPress` hook --- .changeset/twelve-windows-search.md | 5 +++++ packages/react/src/hooks/useKeyPress.ts | 29 ++++++++++++++++++------- 2 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 .changeset/twelve-windows-search.md diff --git a/.changeset/twelve-windows-search.md b/.changeset/twelve-windows-search.md new file mode 100644 index 00000000..cc8b74c7 --- /dev/null +++ b/.changeset/twelve-windows-search.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `type UseKeyPressOptions` and `useKeyPress` hook diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index ec12e562..d7e022fa 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -6,7 +6,16 @@ type PressedKeys = Set; type KeyOrCode = 'key' | 'code'; export type UseKeyPressOptions = { + /** + * You may want to listen to key presses on a specific element. This field lets you configure + * that! + * @default document + */ target?: Window | Document | HTMLElement | ShadowRoot | null; + /** + * You can use this flag to prevent triggering the key press hook when an input field is focused. + * @default true + */ actInsideInputWithModifier?: boolean; preventDefault?: boolean; }; @@ -18,9 +27,7 @@ const defaultDoc = typeof document !== 'undefined' ? document : null; * currently pressed or not. * * @public - * @param param.keyCode - The key code (string or array of strings) to use - * @param param.options - Options - * @returns boolean + * @param options - Options * * @example * ```tsx @@ -40,11 +47,17 @@ const defaultDoc = typeof document !== 'undefined' ? document : null; *``` */ export function useKeyPress( - /* - * the keycode can be a string 'a' or an array of strings ['a', 'a+d'] - * a string means a single key 'a' or a combination when '+' is used 'a+d' - * an array means different possibilites. Explainer: ['a', 'd+s'] here the - * user can use the single key 'a' or the combination 'd' + 's' + /** + * The key code (string or array of strings) specifies which key(s) should trigger + * an action. + * + * A **string** can represent: + * - A **single key**, e.g. `'a'` + * - A **key combination**, using `'+'` to separate keys, e.g. `'a+d'` + * + * An **array of strings** represents **multiple possible key inputs**. For example, `['a', 'd+s']` + * means the user can press either the single key `'a'` or the combination of `'d'` and `'s'`. + * @default null */ keyCode: KeyCode | null = null, options: UseKeyPressOptions = { target: defaultDoc, actInsideInputWithModifier: true } From 29f4aeb260df0a5d83e775c7c2ed788f997006a7 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:29:43 +0200 Subject: [PATCH 140/157] Improve TSDoc comments for `type UseNodeConnectionsParams` and `useNodeConnections` hook --- .changeset/nasty-eagles-hang.md | 5 +++++ packages/react/src/hooks/useNodeConnections.ts | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .changeset/nasty-eagles-hang.md diff --git a/.changeset/nasty-eagles-hang.md b/.changeset/nasty-eagles-hang.md new file mode 100644 index 00000000..de18b242 --- /dev/null +++ b/.changeset/nasty-eagles-hang.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `type UseNodeConnectionsParams` and `useNodeConnections` hook diff --git a/packages/react/src/hooks/useNodeConnections.ts b/packages/react/src/hooks/useNodeConnections.ts index 6d6ad6b9..6a8155ab 100644 --- a/packages/react/src/hooks/useNodeConnections.ts +++ b/packages/react/src/hooks/useNodeConnections.ts @@ -14,10 +14,15 @@ import { useNodeId } from '../contexts/NodeIdContext'; const error014 = errorMessages['error014'](); type UseNodeConnectionsParams = { + /** ID of the node, filled in automatically if used inside custom node. */ id?: string; + /** What type of handle connections do you want to observe? */ handleType?: HandleType; + /** Filter by handle id (this is only needed if the node has multiple handles of the same type). */ handleId?: string; + /** Gets called when a connection is established. */ onConnect?: (connections: Connection[]) => void; + /** Gets called when a connection is removed. */ onDisconnect?: (connections: Connection[]) => void; }; @@ -25,12 +30,7 @@ type UseNodeConnectionsParams = { * This hook returns an array of connections on a specific node, handle type ('source', 'target') or handle ID. * * @public - * @param param.id - node id - optional if called inside a custom node - * @param param.handleType - filter by handle type 'source' or 'target' - * @param param.handleId - filter by handle id (this is only needed if the node has multiple handles of the same type) - * @param param.onConnect - gets called when a connection is established - * @param param.onDisconnect - gets called when a connection is removed - * @returns an array with connections + * @returns An array with connections. * * @example * ```jsx @@ -73,7 +73,7 @@ export function useNodeConnections({ ); useEffect(() => { - // @todo dicuss if onConnect/onDisconnect should be called when the component mounts/unmounts + // @todo discuss if onConnect/onDisconnect should be called when the component mounts/unmounts if (prevConnections.current && prevConnections.current !== connections) { const _connections = connections ?? new Map(); handleConnectionChange(prevConnections.current, _connections, onDisconnect); From ab800054a50c68f9c27dfad2b0d3833b782f4797 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:31:46 +0200 Subject: [PATCH 141/157] Improve TSDoc comments for `useNodesState` and `useEdgesState` hook --- .changeset/heavy-mirrors-draw.md | 5 +++ .../react/src/hooks/useNodesEdgesState.ts | 40 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 .changeset/heavy-mirrors-draw.md diff --git a/.changeset/heavy-mirrors-draw.md b/.changeset/heavy-mirrors-draw.md new file mode 100644 index 00000000..ccb9ae31 --- /dev/null +++ b/.changeset/heavy-mirrors-draw.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `useNodesState` and `useEdgesState` hook diff --git a/packages/react/src/hooks/useNodesEdgesState.ts b/packages/react/src/hooks/useNodesEdgesState.ts index b5919e5e..21d9d108 100644 --- a/packages/react/src/hooks/useNodesEdgesState.ts +++ b/packages/react/src/hooks/useNodesEdgesState.ts @@ -9,8 +9,16 @@ import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; * like React's `useState` hook with an additional helper callback. * * @public - * @param initialNodes - * @returns an array [nodes, setNodes, onNodesChange] + * @returns + * - `nodes`: The current array of nodes. You might pass this directly to the `nodes` prop of your + * `` component, or you may want to manipulate it first to perform some layouting, + * for example. + * - `setNodes`: A function that you can use to update the nodes. You can pass it a new array of + * nodes or a callback that receives the current array of nodes and returns a new array of nodes. + * This is the same as the second element of the tuple returned by React's `useState` hook. + * - `onNodesChange`: A handy callback that can take an array of `NodeChanges` and update the nodes + * state accordingly. You'll typically pass this directly to the `onNodesChange` prop of your + * `` component. * @example * *```tsx @@ -42,7 +50,12 @@ import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; */ export function useNodesState( initialNodes: NodeType[] -): [NodeType[], Dispatch>, OnNodesChange] { +): [ + // + nodes: NodeType[], + setNodes: Dispatch>, + onNodesChange: OnNodesChange +] { const [nodes, setNodes] = useState(initialNodes); const onNodesChange: OnNodesChange = useCallback( (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), @@ -58,8 +71,18 @@ export function useNodesState( * like React's `useState` hook with an additional helper callback. * * @public - * @param initialEdges - * @returns an array [edges, setEdges, onEdgesChange] + * @returns + * - `edges`: The current array of edges. You might pass this directly to the `edges` prop of your + * `` component, or you may want to manipulate it first to perform some layouting, + * for example. + * + * - `setEdges`: A function that you can use to update the edges. You can pass it a new array of + * edges or a callback that receives the current array of edges and returns a new array of edges. + * This is the same as the second element of the tuple returned by React's `useState` hook. + * + * - `onEdgesChange`: A handy callback that can take an array of `EdgeChanges` and update the edges + * state accordingly. You'll typically pass this directly to the `onEdgesChange` prop of your + * `` component. * @example * *```tsx @@ -91,7 +114,12 @@ export function useNodesState( */ export function useEdgesState( initialEdges: EdgeType[] -): [EdgeType[], Dispatch>, OnEdgesChange] { +): [ + // + edges: EdgeType[], + setEdges: Dispatch>, + onEdgesChange: OnEdgesChange +] { const [edges, setEdges] = useState(initialEdges); const onEdgesChange: OnEdgesChange = useCallback( (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), From 09021550dc72ac240fcbb6adb3cf530d91575f79 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:34:06 +0200 Subject: [PATCH 142/157] Improve TSDoc comments for `type UseOnViewportChangeOptions` and `useOnViewportChange` hook --- .changeset/purple-bees-laugh.md | 5 +++++ packages/react/src/hooks/useOnViewportChange.ts | 11 +++++------ 2 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 .changeset/purple-bees-laugh.md diff --git a/.changeset/purple-bees-laugh.md b/.changeset/purple-bees-laugh.md new file mode 100644 index 00000000..99e6d107 --- /dev/null +++ b/.changeset/purple-bees-laugh.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `type UseOnViewportChangeOptions` and `useOnViewportChange` hook diff --git a/packages/react/src/hooks/useOnViewportChange.ts b/packages/react/src/hooks/useOnViewportChange.ts index c82eb344..9a13c4fb 100644 --- a/packages/react/src/hooks/useOnViewportChange.ts +++ b/packages/react/src/hooks/useOnViewportChange.ts @@ -4,21 +4,20 @@ import type { OnViewportChange } from '@xyflow/system'; import { useStoreApi } from './useStore'; export type UseOnViewportChangeOptions = { + /** Gets called when the viewport starts changing. */ onStart?: OnViewportChange; + /** Gets called when the viewport changes. */ onChange?: OnViewportChange; + /** Gets called when the viewport stops changing. */ onEnd?: OnViewportChange; }; /** * The `useOnViewportChange` hook lets you listen for changes to the viewport such - *as panning and zooming. You can provide a callback for each phase of a viewport - *change: `onStart`, `onChange`, and `onEnd`. + * as panning and zooming. You can provide a callback for each phase of a viewport + * change: `onStart`, `onChange`, and `onEnd`. * * @public - * @param params.onStart - gets called when the viewport starts changing - * @param params.onChange - gets called when the viewport changes - * @param params.onEnd - gets called when the viewport stops changing - * * @example * ```jsx *import { useCallback } from 'react'; From d536abea9240bad7f5c1064efc0a4713ebef87d1 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:37:43 +0200 Subject: [PATCH 143/157] Improve TSDoc comments for `useViewport`, `useUpdateNodeInternals`, `useOnSelectionChange`, `useNodesInitialized` hooks and `UseOnSelectionChangeOptions`, `UseNodesInitializedOptions` types --- .changeset/beige-apes-repair.md | 5 +++++ packages/react/src/hooks/useNodesInitialized.ts | 5 +++-- packages/react/src/hooks/useOnSelectionChange.ts | 3 +-- packages/react/src/hooks/useUpdateNodeInternals.ts | 9 +++++---- packages/react/src/hooks/useViewport.ts | 6 +++--- 5 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 .changeset/beige-apes-repair.md diff --git a/.changeset/beige-apes-repair.md b/.changeset/beige-apes-repair.md new file mode 100644 index 00000000..252866a3 --- /dev/null +++ b/.changeset/beige-apes-repair.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `useViewport`, `useUpdateNodeInternals`, `useOnSelectionChange`, `useNodesInitialized` hooks and `UseOnSelectionChangeOptions`, `UseNodesInitializedOptions` types diff --git a/packages/react/src/hooks/useNodesInitialized.ts b/packages/react/src/hooks/useNodesInitialized.ts index 38f15a60..a44ab658 100644 --- a/packages/react/src/hooks/useNodesInitialized.ts +++ b/packages/react/src/hooks/useNodesInitialized.ts @@ -4,6 +4,7 @@ import { useStore } from './useStore'; import type { ReactFlowState } from '../types'; export type UseNodesInitializedOptions = { + /** @default false */ includeHiddenNodes?: boolean; }; @@ -29,8 +30,8 @@ const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) => *`false` and then `true` again once the node has been measured. * * @public - * @param options.includeHiddenNodes - defaults to false - * @returns boolean indicating whether all nodes are initialized + * @returns Whether or not the nodes have been initialized by the `` component and + * given a width and height. * * @example * ```jsx diff --git a/packages/react/src/hooks/useOnSelectionChange.ts b/packages/react/src/hooks/useOnSelectionChange.ts index 17232895..feff9fe3 100644 --- a/packages/react/src/hooks/useOnSelectionChange.ts +++ b/packages/react/src/hooks/useOnSelectionChange.ts @@ -4,6 +4,7 @@ import { useStoreApi } from './useStore'; import type { OnSelectionChangeFunc, Node, Edge } from '../types'; export type UseOnSelectionChangeOptions = { + /** The handler to register. */ onChange: OnSelectionChangeFunc; }; @@ -13,8 +14,6 @@ export type UseOnSelectionChangeOptions ({ /** * The `useViewport` hook is a convenient way to read the current state of the - *{@link Viewport} in a component. Components that use this hook - *will re-render **whenever the viewport changes**. + * {@link Viewport} in a component. Components that use this hook + * will re-render **whenever the viewport changes**. * * @public - * @returns The current viewport + * @returns The current viewport. * * @example * From 701ad17ed3f523389e7d0bf9a006bef249645c3d Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:40:58 +0200 Subject: [PATCH 144/157] Improve TSDoc comments for type `useStore` hook --- .changeset/red-scissors-visit.md | 5 +++++ packages/react/src/hooks/useStore.ts | 13 ++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 .changeset/red-scissors-visit.md diff --git a/.changeset/red-scissors-visit.md b/.changeset/red-scissors-visit.md new file mode 100644 index 00000000..28583d75 --- /dev/null +++ b/.changeset/red-scissors-visit.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for type `useStore` hook diff --git a/packages/react/src/hooks/useStore.ts b/packages/react/src/hooks/useStore.ts index 3b0a2778..f18fb9db 100644 --- a/packages/react/src/hooks/useStore.ts +++ b/packages/react/src/hooks/useStore.ts @@ -14,9 +14,13 @@ const zustandErrorMessage = errorMessages['error001'](); * state management library, so you should check out their docs for more details. * * @public - * @param selector - * @param equalityFn - * @returns The selected state slice + * @param selector - A selector function that returns a slice of the flow's internal state. + * Extracting or transforming just the state you need is a good practice to avoid unnecessary + * re-renders. + * @param equalityFn - A function to compare the previous and next value. This is incredibly useful + * for preventing unnecessary re-renders. Good sensible defaults are using `Object.is` or importing + * `zustand/shallow`, but you can be as granular as you like. + * @returns The selected state slice. * * @example * ```ts @@ -43,8 +47,7 @@ function useStore( /** * In some cases, you might need to access the store directly. This hook returns the store object which can be used on demand to access the state or dispatch actions. * - * @returns The store object - * + * @returns The store object. * @example * ```ts * const store = useStoreApi(); From 67e5ce68284dc71f569ff9156ac69644cdb53dd8 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:42:37 +0200 Subject: [PATCH 145/157] Update .changeset/red-scissors-visit.md --- .changeset/red-scissors-visit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/red-scissors-visit.md b/.changeset/red-scissors-visit.md index 28583d75..5f80f599 100644 --- a/.changeset/red-scissors-visit.md +++ b/.changeset/red-scissors-visit.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -Improve TSDoc comments for type `useStore` hook +Improve TSDoc comments for `useStore` hook From 934ea42d9af6027a3164e1196a78140bdd05d347 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 5 Apr 2025 17:44:33 +0200 Subject: [PATCH 146/157] Improve TSDoc comments for `useEdges`, `useInternalNode`, `useNodes` and `useNodeId` hooks --- .changeset/gorgeous-hats-count.md | 5 +++++ packages/react/src/contexts/NodeIdContext.ts | 2 +- packages/react/src/hooks/useEdges.ts | 2 +- packages/react/src/hooks/useInternalNode.ts | 4 ++-- packages/react/src/hooks/useNodes.ts | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .changeset/gorgeous-hats-count.md diff --git a/.changeset/gorgeous-hats-count.md b/.changeset/gorgeous-hats-count.md new file mode 100644 index 00000000..ce00df81 --- /dev/null +++ b/.changeset/gorgeous-hats-count.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `useEdges`, `useInternalNode`, `useNodes` and `useNodeId` hooks diff --git a/packages/react/src/contexts/NodeIdContext.ts b/packages/react/src/contexts/NodeIdContext.ts index 5458c98c..4fdef045 100644 --- a/packages/react/src/contexts/NodeIdContext.ts +++ b/packages/react/src/contexts/NodeIdContext.ts @@ -10,7 +10,7 @@ export const Consumer = NodeIdContext.Consumer; * drill down the id as a prop. * * @public - * @returns id of the node + * @returns The id for a node in the flow. * * @example *```jsx diff --git a/packages/react/src/hooks/useEdges.ts b/packages/react/src/hooks/useEdges.ts index 45263849..46db9939 100644 --- a/packages/react/src/hooks/useEdges.ts +++ b/packages/react/src/hooks/useEdges.ts @@ -10,7 +10,7 @@ const edgesSelector = (state: ReactFlowState) => state.edges; * will re-render **whenever any edge changes**. * * @public - * @returns An array of edges + * @returns An array of all edges currently in the flow. * * @example * ```tsx diff --git a/packages/react/src/hooks/useInternalNode.ts b/packages/react/src/hooks/useInternalNode.ts index ecd83897..a4678aaa 100644 --- a/packages/react/src/hooks/useInternalNode.ts +++ b/packages/react/src/hooks/useInternalNode.ts @@ -10,8 +10,8 @@ import type { InternalNode, Node } from '../types'; * including when a node is selected or moved. * * @public - * @param id - id of the node - * @returns array with visible node ids + * @param id - The ID of a node you want to observe. + * @returns The `InternalNode` object for the node with the given ID. * * @example * ```tsx diff --git a/packages/react/src/hooks/useNodes.ts b/packages/react/src/hooks/useNodes.ts index 9fa14bcb..6166327d 100644 --- a/packages/react/src/hooks/useNodes.ts +++ b/packages/react/src/hooks/useNodes.ts @@ -11,7 +11,7 @@ const nodesSelector = (state: ReactFlowState) => state.nodes; * or moved. * * @public - * @returns An array of nodes + * @returns An array of all nodes currently in the flow. * * @example * ```jsx From cbe305e15a5c5d3b92583e0ec12364b2509f49bd Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 04:37:13 +0200 Subject: [PATCH 147/157] Improve TSDoc comments for `getOutgoers`, `getIncomers` and `type GetNodesBoundsParams` --- .changeset/empty-buses-admire.md | 5 ++++ packages/system/src/utils/graph.ts | 37 ++++++++++++++++-------------- 2 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 .changeset/empty-buses-admire.md diff --git a/.changeset/empty-buses-admire.md b/.changeset/empty-buses-admire.md new file mode 100644 index 00000000..e0af932b --- /dev/null +++ b/.changeset/empty-buses-admire.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Improve TSDoc comments for `getOutgoers`, `getIncomers` and `type GetNodesBoundsParams` diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index e14f81cd..9bd7beff 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -30,7 +30,7 @@ import { import { errorMessages } from '../constants'; /** - * Test whether an object is useable as an Edge + * Test whether an object is usable as an Edge * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true * @param element - The element to test @@ -40,7 +40,7 @@ export const isEdgeBase = (element: any): 'id' in element && 'source' in element && 'target' in element; /** - * Test whether an object is useable as a Node + * Test whether an object is usable as a Node * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true * @param element - The element to test @@ -57,10 +57,10 @@ export const isInternalNodeBase = = { + /** + * Origin of the nodes: `[0, 0]` for top-left, `[0.5, 0.5]` for center. + * @default [0, 0] + */ nodeOrigin?: NodeOrigin; nodeLookup?: NodeLookup>; }; @@ -159,9 +163,8 @@ export type GetNodesBoundsParams = { * to calculate the correct transform to fit the given nodes in a viewport. * @public * @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport. - * @param nodes - Nodes to calculate the bounds for - * @param params.nodeOrigin - Origin of the nodes: [0, 0] - top left, [0.5, 0.5] - center - * @returns Bounding box enclosing all nodes + * @param nodes - Nodes to calculate the bounds for. + * @returns Bounding box enclosing all nodes. * * @remarks This function was previously called `getRectOfNodes` * @@ -191,7 +194,7 @@ export type GetNodesBoundsParams = { */ export const getNodesBounds = ( nodes: (NodeType | InternalNodeBase | string)[], - params: GetNodesBoundsParams = { nodeOrigin: [0, 0], nodeLookup: undefined } + params: GetNodesBoundsParams = { nodeOrigin: [0, 0] } ): Rect => { if (process.env.NODE_ENV === 'development' && !params.nodeLookup) { console.warn( @@ -299,9 +302,9 @@ export const getNodesInside = ( * This utility filters an array of edges, keeping only those where either the source or target * node is present in the given array of nodes. * @public - * @param nodes - Nodes you want to get the connected edges for - * @param edges - All edges - * @returns Array of edges that connect any of the given nodes with each other + * @param nodes - Nodes you want to get the connected edges for. + * @param edges - All edges. + * @returns Array of edges that connect any of the given nodes with each other. * * @example * ```js From 1f671bd48f06230da841fdd1d7a312413ef16d03 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 04:41:00 +0200 Subject: [PATCH 148/157] Improve TSDoc comments for `type ReconnectEdgeOptions` and `getViewportForBounds` --- .changeset/lazy-avocados-talk.md | 5 +++++ packages/system/src/utils/edges/general.ts | 19 +++++++++++-------- packages/system/src/utils/general.ts | 16 ++++++++-------- 3 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 .changeset/lazy-avocados-talk.md diff --git a/.changeset/lazy-avocados-talk.md b/.changeset/lazy-avocados-talk.md new file mode 100644 index 00000000..f17b232f --- /dev/null +++ b/.changeset/lazy-avocados-talk.md @@ -0,0 +1,5 @@ +--- +'@xyflow/system': patch +--- + +Improve TSDoc comments for `type ReconnectEdgeOptions` and `getViewportForBounds` diff --git a/packages/system/src/utils/edges/general.ts b/packages/system/src/utils/edges/general.ts index 7f98d00f..c094ab0b 100644 --- a/packages/system/src/utils/edges/general.ts +++ b/packages/system/src/utils/edges/general.ts @@ -92,9 +92,9 @@ const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => { /** * This util is a convenience function to add a new Edge to an array of edges. It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one. * @public - * @param edgeParams - Either an Edge or a Connection you want to add - * @param edges - The array of all current edges - * @returns A new array of edges with the new edge added + * @param edgeParams - Either an `Edge` or a `Connection` you want to add. + * @param edges - The array of all current edges. + * @returns A new array of edges with the new edge added. * * @remarks If an edge with the same `target` and `source` already exists (and the same *`targetHandle` and `sourceHandle` if those are set), then this util won't add @@ -137,6 +137,10 @@ export const addEdge = ( }; export type ReconnectEdgeOptions = { + /** + * Should the id of the old edge be replaced with the new connection id. + * @default true + */ shouldReplaceId?: boolean; }; @@ -145,11 +149,10 @@ export type ReconnectEdgeOptions = { *This searches your edge array for an edge with a matching `id` and updates its *properties with the connection you provide. * @public - * @param oldEdge - The edge you want to update - * @param newConnection - The new connection you want to update the edge with - * @param edges - The array of all current edges - * @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id - * @returns the updated edges array + * @param oldEdge - The edge you want to update. + * @param newConnection - The new connection you want to update the edge with. + * @param edges - The array of all current edges. + * @returns The updated edges array. * * @example * ```js diff --git a/packages/system/src/utils/general.ts b/packages/system/src/utils/general.ts index 5b4c6995..67743b5d 100644 --- a/packages/system/src/utils/general.ts +++ b/packages/system/src/utils/general.ts @@ -275,16 +275,16 @@ function calculateAppliedPaddings(bounds: Rect, x: number, y: number, zoom: numb } /** - * Returns a viewport that encloses the given bounds with optional padding. + * Returns a viewport that encloses the given bounds with padding. * @public * @remarks You can determine bounds of nodes with {@link getNodesBounds} and {@link getBoundsOfRects} - * @param bounds - Bounds to fit inside viewport - * @param width - Width of the viewport - * @param height - Height of the viewport - * @param minZoom - Minimum zoom level of the resulting viewport - * @param maxZoom - Maximum zoom level of the resulting viewport - * @param padding - Optional padding around the bounds - * @returns A transforned {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport} + * @param bounds - Bounds to fit inside viewport. + * @param width - Width of the viewport. + * @param height - Height of the viewport. + * @param minZoom - Minimum zoom level of the resulting viewport. + * @param maxZoom - Maximum zoom level of the resulting viewport. + * @param padding - Padding around the bounds. + * @returns A transformed {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport}. * @example * const { x, y, zoom } = getViewportForBounds( * { x: 0, y: 0, width: 100, height: 100}, From eb2a33c6dfb0629e851ab3a0f2cd70eca92efc42 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 04:46:01 +0200 Subject: [PATCH 149/157] Improve TSDoc comments for `interface GetSimpleBezierPathParams` and `getSimpleBezierPath` --- .changeset/tall-dryers-smell.md | 5 +++++ .../src/components/Edges/SimpleBezierEdge.tsx | 14 ++++++++++++-- .../react/src/components/StoreUpdater/index.tsx | 2 +- packages/react/src/utils/changes.ts | 12 ++++++------ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 .changeset/tall-dryers-smell.md diff --git a/.changeset/tall-dryers-smell.md b/.changeset/tall-dryers-smell.md new file mode 100644 index 00000000..8c34da74 --- /dev/null +++ b/.changeset/tall-dryers-smell.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `interface GetSimpleBezierPathParams` and `getSimpleBezierPath` diff --git a/packages/react/src/components/Edges/SimpleBezierEdge.tsx b/packages/react/src/components/Edges/SimpleBezierEdge.tsx index a11cbc1d..3d1cdb3d 100644 --- a/packages/react/src/components/Edges/SimpleBezierEdge.tsx +++ b/packages/react/src/components/Edges/SimpleBezierEdge.tsx @@ -7,9 +7,11 @@ import type { SimpleBezierEdgeProps } from '../../types'; export interface GetSimpleBezierPathParams { sourceX: number; sourceY: number; + /** @default Position.Bottom */ sourcePosition?: Position; targetX: number; targetY: number; + /** @default Position.Top */ targetPosition?: Position; } @@ -33,6 +35,14 @@ function getControl({ pos, x1, y1, x2, y2 }: GetControlParams): [number, number] * The `getSimpleBezierPath` util returns everything you need to render a simple * bezier edge between two nodes. * @public + * @returns + * - `path`: the path to use in an SVG `` element. + * - `labelX`: the `x` position you can use to render a label for this edge. + * - `labelY`: the `y` position you can use to render a label for this edge. + * - `offsetX`: the absolute difference between the source `x` position and the `x` position of the + * middle of this path. + * - `offsetY`: the absolute difference between the source `y` position and the `y` position of the + * middle of this path. */ export function getSimpleBezierPath({ sourceX, @@ -85,8 +95,8 @@ function createSimpleBezierEdge(params: { isInternal: boolean }) { sourceY, targetX, targetY, - sourcePosition = Position.Bottom, - targetPosition = Position.Top, + sourcePosition, + targetPosition, label, labelStyle, labelShowBg, diff --git a/packages/react/src/components/StoreUpdater/index.tsx b/packages/react/src/components/StoreUpdater/index.tsx index ac9122ba..5cad0358 100644 --- a/packages/react/src/components/StoreUpdater/index.tsx +++ b/packages/react/src/components/StoreUpdater/index.tsx @@ -11,7 +11,7 @@ import { useStore, useStoreApi } from '../../hooks/useStore'; import type { Node, Edge, ReactFlowState, ReactFlowProps, FitViewOptions } from '../../types'; import { defaultNodeOrigin } from '../../container/ReactFlow/init-values'; -// these fields exist in the global store and we need to keep them up to date +// These fields exist in the global store, and we need to keep them up to date const reactFlowFieldsToTrack = [ 'nodes', 'edges', diff --git a/packages/react/src/utils/changes.ts b/packages/react/src/utils/changes.ts index 0bc30e46..f1494bf4 100644 --- a/packages/react/src/utils/changes.ts +++ b/packages/react/src/utils/changes.ts @@ -147,9 +147,9 @@ function applyChange(change: any, element: any): any { /** * Drop in function that applies node changes to an array of nodes. * @public - * @param changes - Array of changes to apply - * @param nodes - Array of nodes to apply the changes to - * @returns Array of updated nodes + * @param changes - Array of changes to apply. + * @param nodes - Array of nodes to apply the changes to. + * @returns Array of updated nodes. * @example *```tsx *import { useState, useCallback } from 'react'; @@ -185,9 +185,9 @@ export function applyNodeChanges( /** * Drop in function that applies edge changes to an array of edges. * @public - * @param changes - Array of changes to apply - * @param edges - Array of edge to apply the changes to - * @returns Array of updated edges + * @param changes - Array of changes to apply. + * @param edges - Array of edge to apply the changes to. + * @returns Array of updated edges. * @example * ```tsx *import { useState, useCallback } from 'react'; From 62d874097337a022bebe54b559834c0d582f435e Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 04:49:08 +0200 Subject: [PATCH 150/157] Improve TSDoc comments for `ReactFlowProps` --- .changeset/bright-rabbits-remember.md | 5 + packages/react/src/types/component-props.ts | 347 +++++++++++++------- 2 files changed, 239 insertions(+), 113 deletions(-) create mode 100644 .changeset/bright-rabbits-remember.md diff --git a/.changeset/bright-rabbits-remember.md b/.changeset/bright-rabbits-remember.md new file mode 100644 index 00000000..b5528761 --- /dev/null +++ b/.changeset/bright-rabbits-remember.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `ReactFlowProps` diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index d558bc47..67a5ec2d 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -54,6 +54,7 @@ export interface ReactFlowProps, 'onError'> { /** * An array of nodes to render in a controlled flow. + * @default [] * @example * const nodes = [ * { @@ -67,6 +68,7 @@ export interface ReactFlowProps; - /** This event handler is called when a user double clicks on a node */ + /** This event handler is called when a user double-clicks on a node. */ onNodeDoubleClick?: NodeMouseHandler; - /** This event handler is called when mouse of a user enters a node */ + /** This event handler is called when mouse of a user enters a node. */ onNodeMouseEnter?: NodeMouseHandler; - /** This event handler is called when mouse of a user moves over a node */ + /** This event handler is called when mouse of a user moves over a node. */ onNodeMouseMove?: NodeMouseHandler; - /** This event handler is called when mouse of a user leaves a node */ + /** This event handler is called when mouse of a user leaves a node. */ onNodeMouseLeave?: NodeMouseHandler; - /** This event handler is called when a user right clicks on a node */ + /** This event handler is called when a user right-clicks on a node. */ onNodeContextMenu?: NodeMouseHandler; - /** This event handler is called when a user starts to drag a node */ + /** This event handler is called when a user starts to drag a node. */ onNodeDragStart?: OnNodeDrag; - /** This event handler is called when a user drags a node */ + /** This event handler is called when a user drags a node. */ onNodeDrag?: OnNodeDrag; - /** This event handler is called when a user stops dragging a node */ + /** This event handler is called when a user stops dragging a node. */ onNodeDragStop?: OnNodeDrag; - /** This event handler is called when a user clicks on an edge */ + /** This event handler is called when a user clicks on an edge. */ onEdgeClick?: (event: ReactMouseEvent, edge: EdgeType) => void; - /** This event handler is called when a user right clicks on an edge */ + /** This event handler is called when a user right-clicks on an edge. */ onEdgeContextMenu?: EdgeMouseHandler; - /** This event handler is called when mouse of a user enters an edge */ + /** This event handler is called when mouse of a user enters an edge. */ onEdgeMouseEnter?: EdgeMouseHandler; - /** This event handler is called when mouse of a user moves over an edge */ + /** This event handler is called when mouse of a user moves over an edge. */ onEdgeMouseMove?: EdgeMouseHandler; - /** This event handler is called when mouse of a user leaves an edge */ + /** This event handler is called when mouse of a user leaves an edge. */ onEdgeMouseLeave?: EdgeMouseHandler; - /** This event handler is called when a user double clicks on an edge */ + /** This event handler is called when a user double-clicks on an edge. */ onEdgeDoubleClick?: EdgeMouseHandler; + /** + * This handler is called when the source or target of a reconnectable edge is dragged from the + * current node. It will fire even if the edge's source or target do not end up changing. + * + * You can use the `reconnectEdge` utility to convert the connection to a new edge. + */ onReconnect?: OnReconnect; + /** + * This event fires when the user begins dragging the source or target of an editable edge. + */ onReconnectStart?: (event: ReactMouseEvent, edge: EdgeType, handleType: HandleType) => void; + /** + * This event fires when the user releases the source or target of an editable edge. It is called + * even if an edge update does not occur. + * + * You can use the fourth `connectionState` parameter to have different behavior when a + * reconnection was unsuccessful. + */ + // @TODO: connectionState outdated info? onReconnectEnd?: (event: MouseEvent | TouchEvent, edge: EdgeType, handleType: HandleType) => void; /** - * This event handler is called when a Node is updated + * Use this event handler to add interactivity to a controlled flow. + * It is called on node drag, select, and move. * @example // Use NodesState hook to create edges and get onNodesChange handler * import ReactFlow, { useNodesState } from '@xyflow/react'; * const [edges, setNodes, onNodesChange] = useNodesState(initialNodes); @@ -154,7 +174,8 @@ export interface ReactFlowProps; /** - * This event handler is called when a Edge is updated + * Use this event handler to add interactivity to a controlled flow. It is called on edge select + * and remove. * @example // Use EdgesState hook to create edges and get onEdgesChange handler * import ReactFlow, { useEdgesState } from '@xyflow/react'; * const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); @@ -171,25 +192,28 @@ export interface ReactFlowProps) */ onEdgesChange?: OnEdgesChange; - /** This event handler gets called when a Node is deleted */ + /** This event handler gets called when a node is deleted. */ onNodesDelete?: OnNodesDelete; - /** This event handler gets called when a Edge is deleted */ + /** This event handler gets called when an edge is deleted. */ onEdgesDelete?: OnEdgesDelete; - /** This event handler gets called when a Node or Edge is deleted */ + /** This event handler gets called when a node or edge is deleted. */ onDelete?: OnDelete; - /** This event handler gets called when a user starts to drag a selection box */ + /** This event handler gets called when a user starts to drag a selection box. */ onSelectionDragStart?: SelectionDragHandler; - /** This event handler gets called when a user drags a selection box */ + /** This event handler gets called when a user drags a selection box. */ onSelectionDrag?: SelectionDragHandler; - /** This event handler gets called when a user stops dragging a selection box */ + /** This event handler gets called when a user stops dragging a selection box. */ onSelectionDragStop?: SelectionDragHandler; onSelectionStart?: (event: ReactMouseEvent) => void; onSelectionEnd?: (event: ReactMouseEvent) => void; + /** + * This event handler is called when a user right-clicks on a node selection. + */ onSelectionContextMenu?: (event: ReactMouseEvent, nodes: NodeType[]) => 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. + * 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'; * @@ -201,50 +225,70 @@ export interface ReactFlowProps) */ onConnect?: OnConnect; - /** This event handler gets called when a user starts to drag a connection line */ + /** This event handler gets called when a user starts to drag a connection line. */ onConnectStart?: OnConnectStart; - /** This event handler gets called when a user stops dragging a connection line */ + /** + * This callback will fire regardless of whether a valid connection could be made or not. You can + * use the second `connectionState` parameter to have different behavior when a connection was + * unsuccessful. + */ onConnectEnd?: OnConnectEnd; onClickConnectStart?: OnConnectStart; onClickConnectEnd?: OnConnectEnd; - /** This event handler gets called when a flow has finished initializing */ + /** + * The `onInit` callback is called when the viewport is initialized. At this point you can use the + * instance to call methods like `fitView` or `zoomTo`. + */ onInit?: OnInit; /** This event handler is called while the user is either panning or zooming the viewport. */ onMove?: OnMove; - /** This event handler gets called when a user starts to pan or zoom the viewport */ + /** This event handler is called when the user begins to pan or zoom the viewport. */ onMoveStart?: OnMoveStart; - /** This event handler gets called when a user stops panning or zooming the viewport */ + /** + * This event handler is called when panning or zooming viewport movement stops. + * If the movement is not user-initiated, the event parameter will be `null`. + */ onMoveEnd?: OnMoveEnd; - /** This event handler gets called when a user changes group of selected elements in the flow */ + /** This event handler gets called when a user changes group of selected elements in the flow. */ onSelectionChange?: OnSelectionChangeFunc; - /** This event handler gets called when user scroll inside the pane */ + /** This event handler gets called when user scroll inside the pane. */ onPaneScroll?: (event?: WheelEvent) => void; - /** This event handler gets called when user clicks inside the pane */ + /** This event handler gets called when user clicks inside the pane. */ onPaneClick?: (event: ReactMouseEvent) => void; - /** This event handler gets called when user right clicks inside the pane */ + /** This event handler gets called when user right clicks inside the pane. */ onPaneContextMenu?: (event: ReactMouseEvent | MouseEvent) => void; - /** This event handler gets called when mouse enters the pane */ + /** This event handler gets called when mouse enters the pane. */ onPaneMouseEnter?: (event: ReactMouseEvent) => void; - /** This event handler gets called when mouse moves over the pane */ + /** This event handler gets called when mouse moves over the pane. */ onPaneMouseMove?: (event: ReactMouseEvent) => void; - /** This event handler gets called when mouse leaves the pane */ + /** This event handler gets called when mouse leaves the pane. */ onPaneMouseLeave?: (event: ReactMouseEvent) => void; /** - * Distance that the mouse can move between mousedown/up that will trigger a click + * Distance that the mouse can move between mousedown/up that will trigger a click. * @default 0 */ paneClickDistance?: number; /** - * Distance that the mouse can move between mousedown/up that will trigger a click + * Distance that the mouse can move between mousedown/up that will trigger a click. * @default 0 */ nodeClickDistance?: number; - /** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */ + /** + * This handler is called before nodes or edges are deleted, allowing the deletion to be aborted + * by returning `false` or modified by returning updated nodes and edges. + */ onBeforeDelete?: OnBeforeDelete; /** * Custom node types to be available in a flow. * - * React Flow matches a node's type to a component in the nodeTypes object. + * 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, + * output: OutputNode, + * group: GroupNode + * } * @example * import CustomNode from './CustomNode'; * @@ -254,7 +298,15 @@ export interface ReactFlowProps; - /** Styles to be applied to the container of the connection line */ + /** Styles to be applied to the container of the connection line. */ connectionLineContainerStyle?: CSSProperties; /** - * 'strict' connection mode will only allow you to connect source handles to target handles. - * - * 'loose' connection mode will allow you to connect handles of any type to one another. + * A loose connection mode will allow you to connect handles with differing types, including + * source-to-source connections. However, it does not support target-to-target connections. Strict + * mode allows only connections between source handles and target handles. * @default 'strict' */ connectionMode?: ConnectionMode; /** - * Pressing down this key deletes all selected nodes & edges. + * If set, pressing the key or chord will delete any selected nodes and edges. Passing an array + * represents multiple keys that can be pressed. + * + * For example, `["Delete", "Backspace"]` will delete selected elements when either key is pressed. * @default 'Backspace' */ deleteKeyCode?: KeyCode | null; /** - * If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false. + * If set, holding this key will let you click and drag to draw a selection box around multiple + * nodes and edges. Passing an array represents multiple keys that can be pressed. * - * By setting this prop to null you can disable this functionality. - * @default 'Space' + * For example, `["Shift", "Meta"]` will allow you to draw a selection box when either key is + * pressed. + * @default 'Shift' */ selectionKeyCode?: KeyCode | null; - /** Select multiple elements with a selection box, without pressing down selectionKey */ + /** + * Select multiple elements with a selection box, without pressing down `selectionKey`. + * @default false + */ selectionOnDrag?: boolean; /** - * When set to "partial", when the user creates a selection box by click and dragging nodes that are only partially in the box are still selected. + * When set to `"partial"`, when the user creates a selection box by click and dragging nodes that + * are only partially in the box are still selected. * @default 'full' */ selectionMode?: SelectionMode; /** - * If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false. + * If a key is set, you can pan the viewport while that key is held down even if `panOnScroll` + * is set to `false`. * - * By setting this prop to null you can disable this functionality. + * By setting this prop to `null` you can disable this functionality. * @default 'Space' */ panActivationKeyCode?: KeyCode | null; /** * Pressing down this key you can select multiple elements by clicking. - * @default 'Meta' for macOS, "Ctrl" for other systems + * @default "Meta" for macOS, "Control" for other systems */ multiSelectionKeyCode?: KeyCode | null; /** - * If a key is set, you can zoom the viewport while that key is held down even if panOnScroll is set to false. + * If a key is set, you can zoom the viewport while that key is held down even if `panOnScroll` + * is set to `false`. * - * By setting this prop to null you can disable this functionality. - * @default 'Meta' for macOS, "Ctrl" for other systems + * By setting this prop to `null` you can disable this functionality. + * @default "Meta" for macOS, "Control" for other systems * */ zoomActivationKeyCode?: KeyCode | null; - /** Set this prop to make the flow snap to the grid */ + /** When enabled, nodes will snap to the grid when dragged. */ snapToGrid?: boolean; /** - * Grid all nodes will snap to + * If `snapToGrid` is enabled, this prop configures the grid that nodes will snap to. * @example [20, 20] */ snapGrid?: SnapGrid; /** - * You can enable this optimisation to instruct Svelte Flow to only render nodes and edges that would be visible in the viewport. + * You can enable this optimisation to instruct React Flow to only render nodes and edges that would be visible in the viewport. * * This might improve performance when you have a large number of nodes and edges but also adds an overhead. * @default false */ onlyRenderVisibleElements?: boolean; /** - * Controls if all nodes should be draggable + * Controls whether all nodes should be draggable or not. Individual nodes can override this + * setting by setting their `draggable` prop. If you want to use the mouse handlers on + * non-draggable nodes, you need to add the `"nopan"` class to those nodes. * @default true */ nodesDraggable?: boolean; /** - * Controls if all nodes should be connectable to each other + * Controls whether all nodes should be connectable or not. Individual nodes can override this + * setting by setting their `connectable` prop. * @default true */ nodesConnectable?: boolean; /** - * Controls if all nodes should be focusable + * When `true`, focus between nodes can be cycled with the `Tab` key and selected with the `Enter` + * key. This option can be overridden by individual nodes by setting their `focusable` prop. * @default true */ nodesFocusable?: boolean; /** - * Defines nodes relative position to its coordinates + * 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 @@ -357,49 +428,57 @@ export interface ReactFlowProps void; /** - * By default the viewport extends infinitely. You can use this prop to set a boundary. + * 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]] */ translateExtent?: CoordinateExtent; @@ -424,51 +504,86 @@ export interface ReactFlowProps true + * If you return `false`, the edge will not be added to your flow. + * If you have custom connection logic its preferred to use this callback over the + * `isValidConnection` prop on the handle component for performance reasons. */ isValidConnection?: IsValidConnection; /** - * With a threshold greater than zero you can control the distinction between node drag and click events. + * 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. * @default 1 */ nodeDragThreshold?: number; - /** Sets a fixed width for the flow */ + /** Sets a fixed width for the flow. */ width?: number; - /** Sets a fixed height for the flow */ + /** Sets a fixed height for the flow. */ height?: number; /** - * Controls color scheme used for styling the flow - * @default 'system' + * Controls color scheme used for styling the flow. + * @default 'light' * @example 'system' | 'light' | 'dark' */ colorMode?: ColorMode; /** - * If set true, some debug information will be logged to the console like which events are fired. - * - * @default undefined + * If set `true`, some debug information will be logged to the console like which events are fired. + * @default false */ debug?: boolean; } From e6139a00d4414ba2c1d3e500cdfa67d7e66e655a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 04:52:08 +0200 Subject: [PATCH 151/157] Improve TSDoc comments for `useNodesData`, `useReactFlow`, `isNode` and `isEdge` --- .changeset/afraid-schools-beg.md | 5 +++++ packages/react/src/hooks/useNodesData.ts | 10 ++++++---- packages/react/src/hooks/useReactFlow.ts | 2 -- packages/react/src/utils/general.ts | 18 +++++++++++------- 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 .changeset/afraid-schools-beg.md diff --git a/.changeset/afraid-schools-beg.md b/.changeset/afraid-schools-beg.md new file mode 100644 index 00000000..a908ace5 --- /dev/null +++ b/.changeset/afraid-schools-beg.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `useNodesData`, `useReactFlow`, `isNode` and `isEdge` diff --git a/packages/react/src/hooks/useNodesData.ts b/packages/react/src/hooks/useNodesData.ts index 1d2aa37e..6503f405 100644 --- a/packages/react/src/hooks/useNodesData.ts +++ b/packages/react/src/hooks/useNodesData.ts @@ -8,11 +8,9 @@ import type { Node } from '../types'; * This hook lets you subscribe to changes of a specific nodes `data` object. * * @public - * @param nodeId - The id (or ids) of the node to get the data from - * @returns An object (or array of object) with {id, type, data} representing each node + * @returns An object (or array of object) with `id`, `type`, `data` representing each node. * * @example - * *```jsx *import { useNodesData } from '@xyflow/react'; * @@ -25,9 +23,13 @@ import type { Node } from '../types'; *``` */ export function useNodesData( + /** The id of the node to get the data from. */ nodeId: string ): Pick | null; -export function useNodesData(nodeIds: string[]): Pick[]; +export function useNodesData( + /** The ids of the nodes to get the data from. */ + nodeIds: string[] +): Pick[]; // eslint-disable-next-line @typescript-eslint/no-explicit-any export function useNodesData(nodeIds: any): any { const nodesData = useStore( diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index a02cbb55..2cfc3430 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -31,8 +31,6 @@ const selector = (s: ReactFlowState) => !!s.panZoom; * This hook returns a ReactFlowInstance that can be used to update nodes and edges, manipulate the viewport, or query the current state of the flow. * * @public - * @returns ReactFlowInstance - * * @example * ```jsx *import { useCallback, useState } from 'react'; diff --git a/packages/react/src/utils/general.ts b/packages/react/src/utils/general.ts index 52d8eee2..c7c8a503 100644 --- a/packages/react/src/utils/general.ts +++ b/packages/react/src/utils/general.ts @@ -4,21 +4,23 @@ import { isNodeBase, isEdgeBase } from '@xyflow/system'; import type { Edge, Node } from '../types'; /** - * Test whether an object is useable as an [`Node`](/api-reference/types/node). + * Test whether an object is usable as an [`Node`](/api-reference/types/node). * In TypeScript this is a type guard that will narrow the type of whatever you pass in to * [`Node`](/api-reference/types/node) if it returns `true`. * * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true - * @param element - The element to test - * @returns A boolean indicating whether the element is an Node + * @param element - The element to test. + * @returns Tests whether the provided value can be used as a `Node`. If you're using TypeScript, + * this function acts as a type guard and will narrow the type of the value to `Node` if it returns + * `true`. * * @example * ```js *import { isNode } from '@xyflow/react'; * *if (isNode(node)) { - * // .. + * // ... *} *``` */ @@ -26,21 +28,23 @@ export const isNode = (element: unknown): element isNodeBase(element); /** - * Test whether an object is useable as an [`Edge`](/api-reference/types/edge). + * Test whether an object is usable as an [`Edge`](/api-reference/types/edge). * In TypeScript this is a type guard that will narrow the type of whatever you pass in to * [`Edge`](/api-reference/types/edge) if it returns `true`. * * @public * @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true * @param element - The element to test - * @returns A boolean indicating whether the element is an Edge + * @returns Tests whether the provided value can be used as an `Edge`. If you're using TypeScript, + * this function acts as a type guard and will narrow the type of the value to `Edge` if it returns + * `true`. * * @example * ```js *import { isEdge } from '@xyflow/react'; * *if (isEdge(edge)) { - * // .. + * // ... *} *``` */ From ae585d136e34c9e9ad9d45f75c059bc5367e73ae Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sun, 6 Apr 2025 15:46:49 +0200 Subject: [PATCH 152/157] Improve TSDoc comments for `BaseEdgeProps` --- .changeset/eighty-foxes-add.md | 5 +++++ packages/react/src/types/edges.ts | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .changeset/eighty-foxes-add.md diff --git a/.changeset/eighty-foxes-add.md b/.changeset/eighty-foxes-add.md new file mode 100644 index 00000000..4f781949 --- /dev/null +++ b/.changeset/eighty-foxes-add.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve TSDoc comments for `BaseEdgeProps` diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 9d601037..ca3f91fe 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -148,7 +148,7 @@ export type EdgeProps = Pick< * @public * @expand */ -export type BaseEdgeProps = Omit, 'd' | 'path'> & +export type BaseEdgeProps = Omit, 'd' | 'path' | 'markerStart' | 'markerEnd'> & EdgeLabelOptions & { /** * The width of the invisible area around the edge that the user can interact with. This is @@ -166,6 +166,16 @@ export type BaseEdgeProps = Omit, 'd' | 'path'> & * be used to generate this string for you. */ path: string; + /** + * The id of the SVG marker to use at the start of the edge. This should be defined in a + * `` element in a separate SVG document or element. + */ + markerStart?: string; + /** + * The id of the SVG marker to use at the end of the edge. This should be defined in a `` + * element in a separate SVG document or element. + */ + markerEnd?: string; }; /** From 06f4dc73a51acef573c9ae0874591b17c54af0c0 Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Sun, 6 Apr 2025 20:59:15 +0200 Subject: [PATCH 153/157] Update packages/react/src/hooks/useKeyPress.ts Co-authored-by: Dimitri POSTOLOV --- packages/react/src/hooks/useKeyPress.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react/src/hooks/useKeyPress.ts b/packages/react/src/hooks/useKeyPress.ts index d7e022fa..d378dab7 100644 --- a/packages/react/src/hooks/useKeyPress.ts +++ b/packages/react/src/hooks/useKeyPress.ts @@ -7,8 +7,7 @@ type KeyOrCode = 'key' | 'code'; export type UseKeyPressOptions = { /** - * You may want to listen to key presses on a specific element. This field lets you configure - * that! + * Listen to key presses on a specific element. * @default document */ target?: Window | Document | HTMLElement | ShadowRoot | null; From abacda38531791ca158ce90ed3809e705a61fe19 Mon Sep 17 00:00:00 2001 From: Moritz Klack Date: Sun, 6 Apr 2025 21:07:04 +0200 Subject: [PATCH 154/157] Update packages/react/src/types/component-props.ts Co-authored-by: Dimitri POSTOLOV --- packages/react/src/types/component-props.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index 67a5ec2d..64b94534 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -149,10 +149,7 @@ export interface ReactFlowProps void; /** * Use this event handler to add interactivity to a controlled flow. From d02371662669aab91cd2ac7c45b412491c3377bd Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 7 Apr 2025 11:24:44 +0200 Subject: [PATCH 155/157] chore(changesets): add --- .changeset/curly-kangaroos-clap.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curly-kangaroos-clap.md diff --git a/.changeset/curly-kangaroos-clap.md b/.changeset/curly-kangaroos-clap.md new file mode 100644 index 00000000..c2e617fc --- /dev/null +++ b/.changeset/curly-kangaroos-clap.md @@ -0,0 +1,5 @@ +--- +'@xyflow/react': patch +--- + +Improve `onNodesChange` docs From f10024f565d3b6881f4ecc7d0c76d59c90f0d7fe Mon Sep 17 00:00:00 2001 From: moklick Date: Mon, 7 Apr 2025 11:29:49 +0200 Subject: [PATCH 156/157] chore(changesets): cleanup --- .changeset/chilly-parrots-rest.md | 2 +- .changeset/curly-kangaroos-clap.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/chilly-parrots-rest.md b/.changeset/chilly-parrots-rest.md index 9801602e..b91eb964 100644 --- a/.changeset/chilly-parrots-rest.md +++ b/.changeset/chilly-parrots-rest.md @@ -2,4 +2,4 @@ '@xyflow/svelte': patch --- -Fix typo `React Flow` -> `Svelte Flow` +Fix typo in TSDoc comments `React Flow` -> `Svelte Flow` diff --git a/.changeset/curly-kangaroos-clap.md b/.changeset/curly-kangaroos-clap.md index c2e617fc..5578a375 100644 --- a/.changeset/curly-kangaroos-clap.md +++ b/.changeset/curly-kangaroos-clap.md @@ -2,4 +2,4 @@ '@xyflow/react': patch --- -Improve `onNodesChange` docs +Improve TSDoc comments for `onNodesChange` From b6144869fd567c7aff9cc2d97f58b8ecfb4ed421 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 7 Apr 2025 09:31:06 +0000 Subject: [PATCH 157/157] chore(packages): bump --- .changeset/afraid-schools-beg.md | 5 ---- .changeset/beige-apes-repair.md | 5 ---- .changeset/bright-rabbits-remember.md | 5 ---- .changeset/chilly-parrots-rest.md | 5 ---- .changeset/curly-kangaroos-clap.md | 5 ---- .changeset/eighty-foxes-add.md | 5 ---- .changeset/empty-apples-push.md | 5 ---- .changeset/empty-buses-admire.md | 5 ---- .changeset/five-students-divide.md | 5 ---- .changeset/gorgeous-hats-count.md | 5 ---- .changeset/heavy-mirrors-draw.md | 5 ---- .changeset/lazy-avocados-talk.md | 5 ---- .changeset/many-chefs-clean.md | 5 ---- .changeset/nasty-eagles-hang.md | 5 ---- .changeset/neat-horses-invite.md | 5 ---- .changeset/purple-bees-laugh.md | 5 ---- .changeset/red-scissors-visit.md | 5 ---- .changeset/rich-mirrors-exist.md | 5 ---- .changeset/tall-dryers-smell.md | 5 ---- .changeset/twelve-windows-search.md | 5 ---- packages/react/CHANGELOG.md | 35 +++++++++++++++++++++++++++ packages/react/package.json | 2 +- packages/svelte/CHANGELOG.md | 9 +++++++ packages/svelte/package.json | 2 +- packages/system/CHANGELOG.md | 14 +++++++++++ packages/system/package.json | 2 +- 26 files changed, 61 insertions(+), 103 deletions(-) delete mode 100644 .changeset/afraid-schools-beg.md delete mode 100644 .changeset/beige-apes-repair.md delete mode 100644 .changeset/bright-rabbits-remember.md delete mode 100644 .changeset/chilly-parrots-rest.md delete mode 100644 .changeset/curly-kangaroos-clap.md delete mode 100644 .changeset/eighty-foxes-add.md delete mode 100644 .changeset/empty-apples-push.md delete mode 100644 .changeset/empty-buses-admire.md delete mode 100644 .changeset/five-students-divide.md delete mode 100644 .changeset/gorgeous-hats-count.md delete mode 100644 .changeset/heavy-mirrors-draw.md delete mode 100644 .changeset/lazy-avocados-talk.md delete mode 100644 .changeset/many-chefs-clean.md delete mode 100644 .changeset/nasty-eagles-hang.md delete mode 100644 .changeset/neat-horses-invite.md delete mode 100644 .changeset/purple-bees-laugh.md delete mode 100644 .changeset/red-scissors-visit.md delete mode 100644 .changeset/rich-mirrors-exist.md delete mode 100644 .changeset/tall-dryers-smell.md delete mode 100644 .changeset/twelve-windows-search.md diff --git a/.changeset/afraid-schools-beg.md b/.changeset/afraid-schools-beg.md deleted file mode 100644 index a908ace5..00000000 --- a/.changeset/afraid-schools-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useNodesData`, `useReactFlow`, `isNode` and `isEdge` diff --git a/.changeset/beige-apes-repair.md b/.changeset/beige-apes-repair.md deleted file mode 100644 index 252866a3..00000000 --- a/.changeset/beige-apes-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useViewport`, `useUpdateNodeInternals`, `useOnSelectionChange`, `useNodesInitialized` hooks and `UseOnSelectionChangeOptions`, `UseNodesInitializedOptions` types diff --git a/.changeset/bright-rabbits-remember.md b/.changeset/bright-rabbits-remember.md deleted file mode 100644 index b5528761..00000000 --- a/.changeset/bright-rabbits-remember.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `ReactFlowProps` diff --git a/.changeset/chilly-parrots-rest.md b/.changeset/chilly-parrots-rest.md deleted file mode 100644 index b91eb964..00000000 --- a/.changeset/chilly-parrots-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/svelte': patch ---- - -Fix typo in TSDoc comments `React Flow` -> `Svelte Flow` diff --git a/.changeset/curly-kangaroos-clap.md b/.changeset/curly-kangaroos-clap.md deleted file mode 100644 index 5578a375..00000000 --- a/.changeset/curly-kangaroos-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `onNodesChange` diff --git a/.changeset/eighty-foxes-add.md b/.changeset/eighty-foxes-add.md deleted file mode 100644 index 4f781949..00000000 --- a/.changeset/eighty-foxes-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `BaseEdgeProps` diff --git a/.changeset/empty-apples-push.md b/.changeset/empty-apples-push.md deleted file mode 100644 index 1ed770ee..00000000 --- a/.changeset/empty-apples-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `type GetSmoothStepPathParams` and `getSmoothStepPath` function diff --git a/.changeset/empty-buses-admire.md b/.changeset/empty-buses-admire.md deleted file mode 100644 index e0af932b..00000000 --- a/.changeset/empty-buses-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `getOutgoers`, `getIncomers` and `type GetNodesBoundsParams` diff --git a/.changeset/five-students-divide.md b/.changeset/five-students-divide.md deleted file mode 100644 index b4e9e528..00000000 --- a/.changeset/five-students-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useConnection` hook diff --git a/.changeset/gorgeous-hats-count.md b/.changeset/gorgeous-hats-count.md deleted file mode 100644 index ce00df81..00000000 --- a/.changeset/gorgeous-hats-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useEdges`, `useInternalNode`, `useNodes` and `useNodeId` hooks diff --git a/.changeset/heavy-mirrors-draw.md b/.changeset/heavy-mirrors-draw.md deleted file mode 100644 index ccb9ae31..00000000 --- a/.changeset/heavy-mirrors-draw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useNodesState` and `useEdgesState` hook diff --git a/.changeset/lazy-avocados-talk.md b/.changeset/lazy-avocados-talk.md deleted file mode 100644 index f17b232f..00000000 --- a/.changeset/lazy-avocados-talk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `type ReconnectEdgeOptions` and `getViewportForBounds` diff --git a/.changeset/many-chefs-clean.md b/.changeset/many-chefs-clean.md deleted file mode 100644 index 85786317..00000000 --- a/.changeset/many-chefs-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `type UseHandleConnectionsParams` and `useHandleConnections` hook diff --git a/.changeset/nasty-eagles-hang.md b/.changeset/nasty-eagles-hang.md deleted file mode 100644 index de18b242..00000000 --- a/.changeset/nasty-eagles-hang.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `type UseNodeConnectionsParams` and `useNodeConnections` hook diff --git a/.changeset/neat-horses-invite.md b/.changeset/neat-horses-invite.md deleted file mode 100644 index b04e58e3..00000000 --- a/.changeset/neat-horses-invite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `type GetStraightPathParams` and `getStraightPath` function diff --git a/.changeset/purple-bees-laugh.md b/.changeset/purple-bees-laugh.md deleted file mode 100644 index 99e6d107..00000000 --- a/.changeset/purple-bees-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `type UseOnViewportChangeOptions` and `useOnViewportChange` hook diff --git a/.changeset/red-scissors-visit.md b/.changeset/red-scissors-visit.md deleted file mode 100644 index 5f80f599..00000000 --- a/.changeset/red-scissors-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `useStore` hook diff --git a/.changeset/rich-mirrors-exist.md b/.changeset/rich-mirrors-exist.md deleted file mode 100644 index 1cff8576..00000000 --- a/.changeset/rich-mirrors-exist.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/system': patch ---- - -Improve TSDoc comments for `type GetBezierPathParams` and `getBezierPath` function diff --git a/.changeset/tall-dryers-smell.md b/.changeset/tall-dryers-smell.md deleted file mode 100644 index 8c34da74..00000000 --- a/.changeset/tall-dryers-smell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `interface GetSimpleBezierPathParams` and `getSimpleBezierPath` diff --git a/.changeset/twelve-windows-search.md b/.changeset/twelve-windows-search.md deleted file mode 100644 index cc8b74c7..00000000 --- a/.changeset/twelve-windows-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@xyflow/react': patch ---- - -Improve TSDoc comments for `type UseKeyPressOptions` and `useKeyPress` hook diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index e875040d..8e49ed34 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,40 @@ # @xyflow/react +## 12.5.5 + +### Patch Changes + +- [#5172](https://github.com/xyflow/xyflow/pull/5172) [`e6139a00`](https://github.com/xyflow/xyflow/commit/e6139a00d4414ba2c1d3e500cdfa67d7e66e655a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useNodesData`, `useReactFlow`, `isNode` and `isEdge` + +- [#5165](https://github.com/xyflow/xyflow/pull/5165) [`d536abea`](https://github.com/xyflow/xyflow/commit/d536abea9240bad7f5c1064efc0a4713ebef87d1) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useViewport`, `useUpdateNodeInternals`, `useOnSelectionChange`, `useNodesInitialized` hooks and `UseOnSelectionChangeOptions`, `UseNodesInitializedOptions` types + +- [#5171](https://github.com/xyflow/xyflow/pull/5171) [`62d87409`](https://github.com/xyflow/xyflow/commit/62d874097337a022bebe54b559834c0d582f435e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `ReactFlowProps` + +- [#5154](https://github.com/xyflow/xyflow/pull/5154) [`d0237166`](https://github.com/xyflow/xyflow/commit/d02371662669aab91cd2ac7c45b412491c3377bd) Thanks [@ibagov](https://github.com/ibagov)! - Improve TSDoc comments for `onNodesChange` + +- [#5174](https://github.com/xyflow/xyflow/pull/5174) [`ae585d13`](https://github.com/xyflow/xyflow/commit/ae585d136e34c9e9ad9d45f75c059bc5367e73ae) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `BaseEdgeProps` + +- [#5159](https://github.com/xyflow/xyflow/pull/5159) [`0c1436d6`](https://github.com/xyflow/xyflow/commit/0c1436d6a371240cfa0adecea573c44fd42df7b3) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useConnection` hook + +- [#5167](https://github.com/xyflow/xyflow/pull/5167) [`934ea42d`](https://github.com/xyflow/xyflow/commit/934ea42d9af6027a3164e1196a78140bdd05d347) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useEdges`, `useInternalNode`, `useNodes` and `useNodeId` hooks + +- [#5163](https://github.com/xyflow/xyflow/pull/5163) [`ab800054`](https://github.com/xyflow/xyflow/commit/ab800054a50c68f9c27dfad2b0d3833b782f4797) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useNodesState` and `useEdgesState` hook + +- [#5160](https://github.com/xyflow/xyflow/pull/5160) [`b357f43d`](https://github.com/xyflow/xyflow/commit/b357f43dfa262205059ac9714198196b4aaf8870) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type UseHandleConnectionsParams` and `useHandleConnections` hook + +- [#5162](https://github.com/xyflow/xyflow/pull/5162) [`29f4aeb2`](https://github.com/xyflow/xyflow/commit/29f4aeb260df0a5d83e775c7c2ed788f997006a7) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type UseNodeConnectionsParams` and `useNodeConnections` hook + +- [#5164](https://github.com/xyflow/xyflow/pull/5164) [`09021550`](https://github.com/xyflow/xyflow/commit/09021550dc72ac240fcbb6adb3cf530d91575f79) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type UseOnViewportChangeOptions` and `useOnViewportChange` hook + +- [#5166](https://github.com/xyflow/xyflow/pull/5166) [`701ad17e`](https://github.com/xyflow/xyflow/commit/701ad17ed3f523389e7d0bf9a006bef249645c3d) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `useStore` hook + +- [#5170](https://github.com/xyflow/xyflow/pull/5170) [`eb2a33c6`](https://github.com/xyflow/xyflow/commit/eb2a33c6dfb0629e851ab3a0f2cd70eca92efc42) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `interface GetSimpleBezierPathParams` and `getSimpleBezierPath` + +- [#5161](https://github.com/xyflow/xyflow/pull/5161) [`c4efe749`](https://github.com/xyflow/xyflow/commit/c4efe749208e854dc9ced5bdd00933269d5b4382) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type UseKeyPressOptions` and `useKeyPress` hook + +- Updated dependencies [[`02a3b746`](https://github.com/xyflow/xyflow/commit/02a3b74645799a3f0ce670b69365fa86ecb0616e), [`cbe305e1`](https://github.com/xyflow/xyflow/commit/cbe305e15a5c5d3b92583e0ec12364b2509f49bd), [`1f671bd4`](https://github.com/xyflow/xyflow/commit/1f671bd48f06230da841fdd1d7a312413ef16d03), [`aaebc462`](https://github.com/xyflow/xyflow/commit/aaebc462951ded8e91374c3e084d77af5ed7380a), [`6ec942fc`](https://github.com/xyflow/xyflow/commit/6ec942fc6501f81009c278cc995764bef3e8d03b)]: + - @xyflow/system@0.0.55 + ## 12.5.4 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 0cd5389d..1f42f3aa 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.5.4", + "version": "12.5.5", "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 82b45d97..b590226d 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,14 @@ # @xyflow/svelte +## 0.1.35 + +### Patch Changes + +- [#5158](https://github.com/xyflow/xyflow/pull/5158) [`06696060`](https://github.com/xyflow/xyflow/commit/0669606050bb2138a44a1591176ac8e16afeb0f1) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Fix typo in TSDoc comments `React Flow` -> `Svelte Flow` + +- Updated dependencies [[`02a3b746`](https://github.com/xyflow/xyflow/commit/02a3b74645799a3f0ce670b69365fa86ecb0616e), [`cbe305e1`](https://github.com/xyflow/xyflow/commit/cbe305e15a5c5d3b92583e0ec12364b2509f49bd), [`1f671bd4`](https://github.com/xyflow/xyflow/commit/1f671bd48f06230da841fdd1d7a312413ef16d03), [`aaebc462`](https://github.com/xyflow/xyflow/commit/aaebc462951ded8e91374c3e084d77af5ed7380a), [`6ec942fc`](https://github.com/xyflow/xyflow/commit/6ec942fc6501f81009c278cc995764bef3e8d03b)]: + - @xyflow/system@0.0.55 + ## 0.1.34 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index e76df3d1..64b3bd30 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.34", + "version": "0.1.35", "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 4db8b580..57cef024 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,19 @@ # @xyflow/system +## 0.0.55 + +### Patch Changes + +- [#5156](https://github.com/xyflow/xyflow/pull/5156) [`02a3b746`](https://github.com/xyflow/xyflow/commit/02a3b74645799a3f0ce670b69365fa86ecb0616e) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type GetSmoothStepPathParams` and `getSmoothStepPath` function + +- [#5168](https://github.com/xyflow/xyflow/pull/5168) [`cbe305e1`](https://github.com/xyflow/xyflow/commit/cbe305e15a5c5d3b92583e0ec12364b2509f49bd) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `getOutgoers`, `getIncomers` and `type GetNodesBoundsParams` + +- [#5169](https://github.com/xyflow/xyflow/pull/5169) [`1f671bd4`](https://github.com/xyflow/xyflow/commit/1f671bd48f06230da841fdd1d7a312413ef16d03) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type ReconnectEdgeOptions` and `getViewportForBounds` + +- [#5155](https://github.com/xyflow/xyflow/pull/5155) [`aaebc462`](https://github.com/xyflow/xyflow/commit/aaebc462951ded8e91374c3e084d77af5ed7380a) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type GetStraightPathParams` and `getStraightPath` function + +- [#5157](https://github.com/xyflow/xyflow/pull/5157) [`6ec942fc`](https://github.com/xyflow/xyflow/commit/6ec942fc6501f81009c278cc995764bef3e8d03b) Thanks [@dimaMachina](https://github.com/dimaMachina)! - Improve TSDoc comments for `type GetBezierPathParams` and `getBezierPath` function + ## 0.0.54 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index f91937a6..81582405 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.54", + "version": "0.0.55", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI",