merge main

This commit is contained in:
peterkogo
2025-01-21 15:37:53 +01:00
22 changed files with 101 additions and 44 deletions
-7
View File
@@ -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.
-6
View File
@@ -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.
@@ -47,7 +47,7 @@ const AddNodeOnEdgeDrop = () => {
(event) => { (event) => {
if (!connectingNodeId.current) return; if (!connectingNodeId.current) return;
const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('react-flow__pane'); const targetIsPane = (event.target as Partial<Element> | null)?.classList?.contains('react-flow__pane');
if (targetIsPane && 'clientX' in event && 'clientY' in event) { if (targetIsPane && 'clientX' in event && 'clientY' in event) {
// we need to remove the wrapper bounds, in order to get the correct position // we need to remove the wrapper bounds, in order to get the correct position
@@ -28,10 +28,11 @@ function CustomHandle({ nodeId, ...handleProps }: HandleProps & { nodeId: string
const CustomNode: FC<NodeProps> = ({ id }) => { const CustomNode: FC<NodeProps> = ({ id }) => {
return ( return (
<div style={{ background: '#333', color: '#fff', padding: 10, fontSize: 12, borderRadius: 10 }}> <div style={{ background: '#333', color: '#fff', padding: 10, fontSize: 12, borderRadius: 10 }}>
<CustomHandle nodeId={id} type="target" position={Position.Left} /> <CustomHandle nodeId={id} type="target" position={Position.Left} id="t1" style={{ top: 10 }} />
<CustomHandle nodeId={id} type="target" position={Position.Left} id="t2" style={{ top: 20 }} />
<div>node {id}</div> <div>node {id}</div>
<CustomHandle nodeId={id} type="source" position={Position.Right} id="a" style={{ top: 10 }} /> <CustomHandle nodeId={id} type="source" position={Position.Right} id="s1" style={{ top: 10 }} />
<CustomHandle nodeId={id} type="source" position={Position.Right} id="b" style={{ top: 20 }} /> <CustomHandle nodeId={id} type="source" position={Position.Right} id="s2" style={{ top: 20 }} />
</div> </div>
); );
}; };
@@ -69,17 +69,16 @@ const initEdges = [
source: '1', source: '1',
target: '3', target: '3',
}, },
{ {
id: 'e4a-5', id: 'e4a-5',
source: '4', source: '4',
sourceHandle: 'a', sourceHandle: 's1',
target: '5', target: '5',
}, },
{ {
id: 'e4b-5', id: 'e4b-5',
source: '4', source: '4',
sourceHandle: 'b', sourceHandle: 's2',
target: '6', target: '6',
}, },
]; ];
@@ -92,6 +91,8 @@ const CustomNodeFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initNodes); const [nodes, setNodes, onNodesChange] = useNodesState(initNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges); const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges);
console.log(edges);
const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]); const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
return ( return (
@@ -37,7 +37,7 @@
if (!connectingNodeId) return; if (!connectingNodeId) return;
// See of connection landed inside the flow pane // 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<Element> | null)?.classList?.contains('svelte-flow__pane');
if (targetIsPane && 'clientX' in event && 'clientY' in event) { if (targetIsPane && 'clientX' in event && 'clientY' in event) {
const id = getId(); const id = getId();
const position = { const position = {
+26
View File
@@ -1,5 +1,31 @@
# @xyflow/react # @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 ## 12.3.6
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/react", "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.", "description": "React Flow - A highly customizable React library for building node-based editors and interactive flow charts.",
"keywords": [ "keywords": [
"react", "react",
@@ -175,7 +175,7 @@ function HandleComponent(
return; return;
} }
const doc = getHostForElement(event.target as HTMLElement); const doc = getHostForElement(event.target);
const isValidConnectionHandler = isValidConnection || isValidConnectionStore; const isValidConnectionHandler = isValidConnection || isValidConnectionStore;
const { connection, isValid } = XYHandle.isValid(event.nativeEvent, { const { connection, isValid } = XYHandle.isValid(event.nativeEvent, {
handle: { handle: {
+2 -2
View File
@@ -131,7 +131,7 @@ export function Pane({
return; return;
} }
(event.target as Element)?.setPointerCapture?.(event.pointerId); (event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId);
selectionStarted.current = true; selectionStarted.current = true;
selectionInProgress.current = false; selectionInProgress.current = false;
@@ -230,7 +230,7 @@ export function Pane({
return; return;
} }
(event.target as Element)?.releasePointerCapture?.(event.pointerId); (event.target as Partial<Element>)?.releasePointerCapture?.(event.pointerId);
const { userSelectionRect } = store.getState(); const { userSelectionRect } = store.getState();
// We only want to trigger click functions when in selection mode if // We only want to trigger click functions when in selection mode if
+1 -1
View File
@@ -85,7 +85,7 @@ export {
type OnResizeEnd, type OnResizeEnd,
type ControlPosition, type ControlPosition,
type ControlLinePosition, type ControlLinePosition,
type ResizeControlVariant, ResizeControlVariant,
type ResizeParams, type ResizeParams,
type ResizeParamsWithDirection, type ResizeParamsWithDirection,
type ResizeDragEvent, type ResizeDragEvent,
+24
View File
@@ -1,5 +1,29 @@
# @xyflow/svelte # @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 ## 0.1.26
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/svelte", "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.", "description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
"keywords": [ "keywords": [
"svelte", "svelte",
@@ -99,7 +99,7 @@
return; return;
} }
(event.target as Element)?.setPointerCapture?.(event.pointerId); (event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId);
const { x, y } = getEventPosition(event, containerBounds); const { x, y } = getEventPosition(event, containerBounds);
@@ -181,7 +181,7 @@
return; return;
} }
(event.target as Element)?.releasePointerCapture?.(event.pointerId); (event.target as Partial<Element> | null)?.releasePointerCapture?.(event.pointerId);
// We only want to trigger click functions when in selection mode if // We only want to trigger click functions when in selection mode if
// the user did not move the mouse. // the user did not move the mouse.
+1 -1
View File
@@ -103,7 +103,7 @@ export {
type OnResizeEnd, type OnResizeEnd,
type ControlPosition, type ControlPosition,
type ControlLinePosition, type ControlLinePosition,
type ResizeControlVariant, ResizeControlVariant,
type ResizeParams, type ResizeParams,
type ResizeParamsWithDirection, type ResizeParamsWithDirection,
type ResizeDragEvent, type ResizeDragEvent,
+16
View File
@@ -1,5 +1,21 @@
# @xyflow/system # @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 ## 0.0.47
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/system", "name": "@xyflow/system",
"version": "0.0.47", "version": "0.0.49",
"description": "xyflow core system that powers React Flow and Svelte Flow.", "description": "xyflow core system that powers React Flow and Svelte Flow.",
"keywords": [ "keywords": [
"node-based UI", "node-based UI",
+7 -5
View File
@@ -32,18 +32,20 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({
height: node.offsetHeight, height: node.offsetHeight,
}); });
export const getHostForElement = (element: HTMLElement): Document | ShadowRoot => export const getHostForElement = (element: HTMLElement | EventTarget | null): Document | ShadowRoot =>
(element.getRootNode?.() as Document | ShadowRoot) || window?.document; ((element as Partial<HTMLElement> | null)?.getRootNode?.() as Document | ShadowRoot) || window?.document;
const inputTags = ['INPUT', 'SELECT', 'TEXTAREA']; const inputTags = ['INPUT', 'SELECT', 'TEXTAREA'];
export function isInputDOMNode(event: KeyboardEvent): boolean { export function isInputDOMNode(event: KeyboardEvent): boolean {
// using composed path for handling shadow dom // using composed path for handling shadow dom
const target = (event.composedPath?.()?.[0] || event.target) as HTMLElement; const target = (event.composedPath?.()?.[0] || event.target) as Element | null;
const isInput = inputTags.includes(target?.nodeName) || target?.hasAttribute?.('contenteditable'); 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 // 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; export const isMouseEvent = (event: MouseEvent | TouchEvent): event is MouseEvent => 'clientX' in event;
+2 -2
View File
@@ -498,8 +498,8 @@ export function updateConnectionLookup(connectionLookup: ConnectionLookup, edgeL
const { source: sourceNode, target: targetNode, sourceHandle = null, targetHandle = null } = edge; const { source: sourceNode, target: targetNode, sourceHandle = null, targetHandle = null } = edge;
const connection = { edgeId: edge.id, source: sourceNode, target: targetNode, sourceHandle, targetHandle }; const connection = { edgeId: edge.id, source: sourceNode, target: targetNode, sourceHandle, targetHandle };
const sourceKey = `${sourceNode}-${sourceHandle}`; const sourceKey = `${sourceNode}-${sourceHandle}--${targetNode}-${targetHandle}`;
const targetKey = `${targetNode}-${targetHandle}`; const targetKey = `${targetNode}-${targetHandle}--${sourceNode}-${sourceHandle}`;
addConnectionToLookup('source', connection, targetKey, connectionLookup, sourceNode, sourceHandle); addConnectionToLookup('source', connection, targetKey, connectionLookup, sourceNode, sourceHandle);
addConnectionToLookup('target', connection, sourceKey, connectionLookup, targetNode, targetHandle); addConnectionToLookup('target', connection, sourceKey, connectionLookup, targetNode, targetHandle);
+1 -1
View File
@@ -364,7 +364,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
} }
}) })
.filter((event: MouseEvent) => { .filter((event: MouseEvent) => {
const target = event.target as HTMLDivElement; const target = event.target;
const isDraggable = const isDraggable =
!event.button && !event.button &&
(!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) && (!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) &&
+4 -4
View File
@@ -18,13 +18,13 @@ export function isParentSelected<NodeType extends NodeBase>(node: NodeType, node
return isParentSelected(parentNode, nodeLookup); return isParentSelected(parentNode, nodeLookup);
} }
export function hasSelector(target: Element, selector: string, domNode: Element): boolean { export function hasSelector(target: Element | EventTarget | null, selector: string, domNode: Element): boolean {
let current = target; let current = target as Partial<Element> | null | undefined;
do { do {
if (current?.matches(selector)) return true; if (current?.matches?.(selector)) return true;
if (current === domNode) return false; if (current === domNode) return false;
current = current.parentElement as Element; current = current?.parentElement;
} while (current); } while (current);
return false; return false;
+1 -1
View File
@@ -48,7 +48,7 @@ function onPointerDown(
}: OnPointerDownParams }: OnPointerDownParams
) { ) {
// when xyflow is used inside a shadow root we can't use document // 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 autoPanId = 0;
let closestHandle: Handle | null; let closestHandle: Handle | null;