diff --git a/.changeset/silly-pots-yell.md b/.changeset/silly-pots-yell.md deleted file mode 100644 index 71848488..00000000 --- a/.changeset/silly-pots-yell.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@xyflow/react': minor -'@xyflow/svelte': patch -'@xyflow/system': patch ---- - -Add useNodeConnections hook to track all connections to a node. Can be filtered by handleType and handleId. diff --git a/.changeset/twelve-bottles-turn.md b/.changeset/twelve-bottles-turn.md deleted file mode 100644 index 89b28a52..00000000 --- a/.changeset/twelve-bottles-turn.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@xyflow/react': patch -'@xyflow/system': patch ---- - -Optimize selections and take into account if edges connected to selected nodes are actually selectable. diff --git a/examples/react/src/examples/AddNodeOnEdgeDrop/index.tsx b/examples/react/src/examples/AddNodeOnEdgeDrop/index.tsx index cdd55a4b..7c0345d2 100644 --- a/examples/react/src/examples/AddNodeOnEdgeDrop/index.tsx +++ b/examples/react/src/examples/AddNodeOnEdgeDrop/index.tsx @@ -47,7 +47,7 @@ const AddNodeOnEdgeDrop = () => { (event) => { if (!connectingNodeId.current) return; - const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('react-flow__pane'); + const targetIsPane = (event.target as Partial | null)?.classList?.contains('react-flow__pane'); if (targetIsPane && 'clientX' in event && 'clientY' in event) { // we need to remove the wrapper bounds, in order to get the correct position diff --git a/examples/react/src/examples/UseNodeConnections/MultiHandleNode.tsx b/examples/react/src/examples/UseNodeConnections/MultiHandleNode.tsx index 5d64f81d..3191221c 100644 --- a/examples/react/src/examples/UseNodeConnections/MultiHandleNode.tsx +++ b/examples/react/src/examples/UseNodeConnections/MultiHandleNode.tsx @@ -28,10 +28,11 @@ function CustomHandle({ nodeId, ...handleProps }: HandleProps & { nodeId: string const CustomNode: FC = ({ id }) => { return (
- + +
node {id}
- - + +
); }; diff --git a/examples/react/src/examples/UseNodeConnections/index.tsx b/examples/react/src/examples/UseNodeConnections/index.tsx index c6aa4a68..6b41018e 100644 --- a/examples/react/src/examples/UseNodeConnections/index.tsx +++ b/examples/react/src/examples/UseNodeConnections/index.tsx @@ -69,17 +69,16 @@ const initEdges = [ source: '1', target: '3', }, - { id: 'e4a-5', source: '4', - sourceHandle: 'a', + sourceHandle: 's1', target: '5', }, { id: 'e4b-5', source: '4', - sourceHandle: 'b', + sourceHandle: 's2', target: '6', }, ]; @@ -92,6 +91,8 @@ const CustomNodeFlow = () => { const [nodes, setNodes, onNodesChange] = useNodesState(initNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges); + console.log(edges); + const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]); return ( diff --git a/examples/svelte/src/routes/examples/add-node-on-drop/Flow.svelte b/examples/svelte/src/routes/examples/add-node-on-drop/Flow.svelte index 26e14f2e..99e83505 100644 --- a/examples/svelte/src/routes/examples/add-node-on-drop/Flow.svelte +++ b/examples/svelte/src/routes/examples/add-node-on-drop/Flow.svelte @@ -37,7 +37,7 @@ if (!connectingNodeId) return; // See of connection landed inside the flow pane - const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('svelte-flow__pane'); + const targetIsPane = (event.target as Partial | null)?.classList?.contains('svelte-flow__pane'); if (targetIsPane && 'clientX' in event && 'clientY' in event) { const id = getId(); const position = { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 259c08b7..abddf7b8 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,31 @@ # @xyflow/react +## 12.4.1 + +### Patch Changes + +- [#4949](https://github.com/xyflow/xyflow/pull/4949) [`592c7eaf`](https://github.com/xyflow/xyflow/commit/592c7eaf9574fc69df3123837da95f85877b23e8) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix useNodeConnection hook not returning all connected edges. + +- Updated dependencies [[`592c7eaf`](https://github.com/xyflow/xyflow/commit/592c7eaf9574fc69df3123837da95f85877b23e8)]: + - @xyflow/system@0.0.49 + +## 12.4.0 + +### Minor Changes + +- [#4725](https://github.com/xyflow/xyflow/pull/4725) [`e10f53cf`](https://github.com/xyflow/xyflow/commit/e10f53cf898a56f954783d6efcf6977a0d88f4a9) Thanks [@peterkogo](https://github.com/peterkogo)! - Add useNodeConnections hook to track all connections to a node. Can be filtered by handleType and handleId. + +### Patch Changes + +- [#4947](https://github.com/xyflow/xyflow/pull/4947) [`868aa3f3`](https://github.com/xyflow/xyflow/commit/868aa3f3db8223ea1b04a68aa027ea99fd1e91c8) Thanks [@moklick](https://github.com/moklick)! - Export ResizeControlVariant correctly as a value. + +- [#4880](https://github.com/xyflow/xyflow/pull/4880) [`e2d849dc`](https://github.com/xyflow/xyflow/commit/e2d849dca63aee5952f676aef1c675c6232bb69a) Thanks [@crimx](https://github.com/crimx)! - Add type check for all event targets + +- [#4929](https://github.com/xyflow/xyflow/pull/4929) [`4947f683`](https://github.com/xyflow/xyflow/commit/4947f683b7530f8e6684865ab53ea38633de0f4d) Thanks [@peterkogo](https://github.com/peterkogo)! - Optimize selections and take into account if edges connected to selected nodes are actually selectable. + +- Updated dependencies [[`e2d849dc`](https://github.com/xyflow/xyflow/commit/e2d849dca63aee5952f676aef1c675c6232bb69a), [`e10f53cf`](https://github.com/xyflow/xyflow/commit/e10f53cf898a56f954783d6efcf6977a0d88f4a9), [`4947f683`](https://github.com/xyflow/xyflow/commit/4947f683b7530f8e6684865ab53ea38633de0f4d)]: + - @xyflow/system@0.0.48 + ## 12.3.6 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 42d5c134..18f629bc 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/react", - "version": "12.3.6", + "version": "12.4.1", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.", "keywords": [ "react", diff --git a/packages/react/src/components/Handle/index.tsx b/packages/react/src/components/Handle/index.tsx index 3ea98530..cc86e189 100644 --- a/packages/react/src/components/Handle/index.tsx +++ b/packages/react/src/components/Handle/index.tsx @@ -175,7 +175,7 @@ function HandleComponent( return; } - const doc = getHostForElement(event.target as HTMLElement); + const doc = getHostForElement(event.target); const isValidConnectionHandler = isValidConnection || isValidConnectionStore; const { connection, isValid } = XYHandle.isValid(event.nativeEvent, { handle: { diff --git a/packages/react/src/container/Pane/index.tsx b/packages/react/src/container/Pane/index.tsx index 3432247b..aeadde03 100644 --- a/packages/react/src/container/Pane/index.tsx +++ b/packages/react/src/container/Pane/index.tsx @@ -131,7 +131,7 @@ export function Pane({ return; } - (event.target as Element)?.setPointerCapture?.(event.pointerId); + (event.target as Partial | null)?.setPointerCapture?.(event.pointerId); selectionStarted.current = true; selectionInProgress.current = false; @@ -230,7 +230,7 @@ export function Pane({ return; } - (event.target as Element)?.releasePointerCapture?.(event.pointerId); + (event.target as Partial)?.releasePointerCapture?.(event.pointerId); const { userSelectionRect } = store.getState(); // We only want to trigger click functions when in selection mode if diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 4cbb393d..a6e3d6d2 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -85,7 +85,7 @@ export { type OnResizeEnd, type ControlPosition, type ControlLinePosition, - type ResizeControlVariant, + ResizeControlVariant, type ResizeParams, type ResizeParamsWithDirection, type ResizeDragEvent, diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 7758855e..736fbc04 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,29 @@ # @xyflow/svelte +## 0.1.28 + +### Patch Changes + +- [#4949](https://github.com/xyflow/xyflow/pull/4949) [`592c7eaf`](https://github.com/xyflow/xyflow/commit/592c7eaf9574fc69df3123837da95f85877b23e8) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix useNodeConnection hook not returning all connected edges. + +- Updated dependencies [[`592c7eaf`](https://github.com/xyflow/xyflow/commit/592c7eaf9574fc69df3123837da95f85877b23e8)]: + - @xyflow/system@0.0.49 + +## 0.1.27 + +### Patch Changes + +- [#4937](https://github.com/xyflow/xyflow/pull/4937) [`9d940300`](https://github.com/xyflow/xyflow/commit/9d940300441b10f4d9eef4b07fac49a3e69d3503) Thanks [@jrmoynihan](https://github.com/jrmoynihan)! - Expose props of Controls + +- [#4947](https://github.com/xyflow/xyflow/pull/4947) [`868aa3f3`](https://github.com/xyflow/xyflow/commit/868aa3f3db8223ea1b04a68aa027ea99fd1e91c8) Thanks [@moklick](https://github.com/moklick)! - Export ResizeControlVariant correctly as a value. + +- [#4880](https://github.com/xyflow/xyflow/pull/4880) [`e2d849dc`](https://github.com/xyflow/xyflow/commit/e2d849dca63aee5952f676aef1c675c6232bb69a) Thanks [@crimx](https://github.com/crimx)! - Add type check for all event targets + +- [#4725](https://github.com/xyflow/xyflow/pull/4725) [`e10f53cf`](https://github.com/xyflow/xyflow/commit/e10f53cf898a56f954783d6efcf6977a0d88f4a9) Thanks [@peterkogo](https://github.com/peterkogo)! - Add useNodeConnections hook to track all connections to a node. Can be filtered by handleType and handleId. + +- Updated dependencies [[`e2d849dc`](https://github.com/xyflow/xyflow/commit/e2d849dca63aee5952f676aef1c675c6232bb69a), [`e10f53cf`](https://github.com/xyflow/xyflow/commit/e10f53cf898a56f954783d6efcf6977a0d88f4a9), [`4947f683`](https://github.com/xyflow/xyflow/commit/4947f683b7530f8e6684865ab53ea38633de0f4d)]: + - @xyflow/system@0.0.48 + ## 0.1.26 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index dd6b58f0..26b45d92 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/svelte", - "version": "0.1.26", + "version": "0.1.28", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.", "keywords": [ "svelte", diff --git a/packages/svelte/src/lib/container/Pane/Pane.svelte b/packages/svelte/src/lib/container/Pane/Pane.svelte index 0f72f7c7..cd9c0653 100644 --- a/packages/svelte/src/lib/container/Pane/Pane.svelte +++ b/packages/svelte/src/lib/container/Pane/Pane.svelte @@ -99,7 +99,7 @@ return; } - (event.target as Element)?.setPointerCapture?.(event.pointerId); + (event.target as Partial | null)?.setPointerCapture?.(event.pointerId); const { x, y } = getEventPosition(event, containerBounds); @@ -181,7 +181,7 @@ return; } - (event.target as Element)?.releasePointerCapture?.(event.pointerId); + (event.target as Partial | null)?.releasePointerCapture?.(event.pointerId); // We only want to trigger click functions when in selection mode if // the user did not move the mouse. diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index 498327c3..6ce24219 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -103,7 +103,7 @@ export { type OnResizeEnd, type ControlPosition, type ControlLinePosition, - type ResizeControlVariant, + ResizeControlVariant, type ResizeParams, type ResizeParamsWithDirection, type ResizeDragEvent, diff --git a/packages/system/CHANGELOG.md b/packages/system/CHANGELOG.md index 6fbc98f9..faeb5e48 100644 --- a/packages/system/CHANGELOG.md +++ b/packages/system/CHANGELOG.md @@ -1,5 +1,21 @@ # @xyflow/system +## 0.0.49 + +### Patch Changes + +- [#4949](https://github.com/xyflow/xyflow/pull/4949) [`592c7eaf`](https://github.com/xyflow/xyflow/commit/592c7eaf9574fc69df3123837da95f85877b23e8) Thanks [@peterkogo](https://github.com/peterkogo)! - Fix useNodeConnection hook not returning all connected edges. + +## 0.0.48 + +### Patch Changes + +- [#4880](https://github.com/xyflow/xyflow/pull/4880) [`e2d849dc`](https://github.com/xyflow/xyflow/commit/e2d849dca63aee5952f676aef1c675c6232bb69a) Thanks [@crimx](https://github.com/crimx)! - Add type check for all event targets + +- [#4725](https://github.com/xyflow/xyflow/pull/4725) [`e10f53cf`](https://github.com/xyflow/xyflow/commit/e10f53cf898a56f954783d6efcf6977a0d88f4a9) Thanks [@peterkogo](https://github.com/peterkogo)! - Add useNodeConnections hook to track all connections to a node. Can be filtered by handleType and handleId. + +- [#4929](https://github.com/xyflow/xyflow/pull/4929) [`4947f683`](https://github.com/xyflow/xyflow/commit/4947f683b7530f8e6684865ab53ea38633de0f4d) Thanks [@peterkogo](https://github.com/peterkogo)! - Optimize selections and take into account if edges connected to selected nodes are actually selectable. + ## 0.0.47 ### Patch Changes diff --git a/packages/system/package.json b/packages/system/package.json index 67a433b0..6169c271 100644 --- a/packages/system/package.json +++ b/packages/system/package.json @@ -1,6 +1,6 @@ { "name": "@xyflow/system", - "version": "0.0.47", + "version": "0.0.49", "description": "xyflow core system that powers React Flow and Svelte Flow.", "keywords": [ "node-based UI", diff --git a/packages/system/src/utils/dom.ts b/packages/system/src/utils/dom.ts index b3648ede..12188e9b 100644 --- a/packages/system/src/utils/dom.ts +++ b/packages/system/src/utils/dom.ts @@ -32,18 +32,20 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({ height: node.offsetHeight, }); -export const getHostForElement = (element: HTMLElement): Document | ShadowRoot => - (element.getRootNode?.() as Document | ShadowRoot) || window?.document; +export const getHostForElement = (element: HTMLElement | EventTarget | null): Document | ShadowRoot => + ((element as Partial | null)?.getRootNode?.() as Document | ShadowRoot) || window?.document; const inputTags = ['INPUT', 'SELECT', 'TEXTAREA']; export function isInputDOMNode(event: KeyboardEvent): boolean { // using composed path for handling shadow dom - const target = (event.composedPath?.()?.[0] || event.target) as HTMLElement; - const isInput = inputTags.includes(target?.nodeName) || target?.hasAttribute?.('contenteditable'); + const target = (event.composedPath?.()?.[0] || event.target) as Element | null; + if (target?.nodeType !== 1 /* Node.ELEMENT_NODE */) return false; + + const isInput = inputTags.includes(target.nodeName) || target.hasAttribute('contenteditable'); // when an input field is focused we don't want to trigger deletion or movement of nodes - return isInput || !!target?.closest('.nokey'); + return isInput || !!target.closest('.nokey'); } export const isMouseEvent = (event: MouseEvent | TouchEvent): event is MouseEvent => 'clientX' in event; diff --git a/packages/system/src/utils/store.ts b/packages/system/src/utils/store.ts index aaa7d627..77c5b369 100644 --- a/packages/system/src/utils/store.ts +++ b/packages/system/src/utils/store.ts @@ -498,8 +498,8 @@ export function updateConnectionLookup(connectionLookup: ConnectionLookup, edgeL const { source: sourceNode, target: targetNode, sourceHandle = null, targetHandle = null } = edge; const connection = { edgeId: edge.id, source: sourceNode, target: targetNode, sourceHandle, targetHandle }; - const sourceKey = `${sourceNode}-${sourceHandle}`; - const targetKey = `${targetNode}-${targetHandle}`; + const sourceKey = `${sourceNode}-${sourceHandle}--${targetNode}-${targetHandle}`; + const targetKey = `${targetNode}-${targetHandle}--${sourceNode}-${sourceHandle}`; addConnectionToLookup('source', connection, targetKey, connectionLookup, sourceNode, sourceHandle); addConnectionToLookup('target', connection, sourceKey, connectionLookup, targetNode, targetHandle); diff --git a/packages/system/src/xydrag/XYDrag.ts b/packages/system/src/xydrag/XYDrag.ts index adf72e5c..eb2ea80a 100644 --- a/packages/system/src/xydrag/XYDrag.ts +++ b/packages/system/src/xydrag/XYDrag.ts @@ -364,7 +364,7 @@ export function XYDrag voi } }) .filter((event: MouseEvent) => { - const target = event.target as HTMLDivElement; + const target = event.target; const isDraggable = !event.button && (!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) && diff --git a/packages/system/src/xydrag/utils.ts b/packages/system/src/xydrag/utils.ts index 0fc048e8..5c0eda0a 100644 --- a/packages/system/src/xydrag/utils.ts +++ b/packages/system/src/xydrag/utils.ts @@ -18,13 +18,13 @@ export function isParentSelected(node: NodeType, node return isParentSelected(parentNode, nodeLookup); } -export function hasSelector(target: Element, selector: string, domNode: Element): boolean { - let current = target; +export function hasSelector(target: Element | EventTarget | null, selector: string, domNode: Element): boolean { + let current = target as Partial | null | undefined; do { - if (current?.matches(selector)) return true; + if (current?.matches?.(selector)) return true; if (current === domNode) return false; - current = current.parentElement as Element; + current = current?.parentElement; } while (current); return false; diff --git a/packages/system/src/xyhandle/XYHandle.ts b/packages/system/src/xyhandle/XYHandle.ts index b15befc9..5f4fc610 100644 --- a/packages/system/src/xyhandle/XYHandle.ts +++ b/packages/system/src/xyhandle/XYHandle.ts @@ -48,7 +48,7 @@ function onPointerDown( }: OnPointerDownParams ) { // when xyflow is used inside a shadow root we can't use document - const doc = getHostForElement(event.target as HTMLElement); + const doc = getHostForElement(event.target); let autoPanId = 0; let closestHandle: Handle | null;