Merge branch 'next' into refactor/edge-rendering
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@xyflow/system",
|
||||
"version": "0.0.10",
|
||||
"version": "0.0.12",
|
||||
"description": "xyflow core system that powers React Flow and Svelte Flow.",
|
||||
"keywords": [
|
||||
"node-based UI",
|
||||
|
||||
@@ -1,33 +1,38 @@
|
||||
.xy-flow {
|
||||
--node-border-default: 1px solid #bbb;
|
||||
--node-border-selected-default: 1px solid #555;
|
||||
--xy-node-border-default: 1px solid #bbb;
|
||||
--xy-node-border-selected-default: 1px solid #555;
|
||||
|
||||
--handle-background-color-default: #333;
|
||||
--xy-handle-background-color-default: #333;
|
||||
|
||||
--selection-background-color-default: rgba(150, 150, 180, 0.1);
|
||||
--selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);
|
||||
--xy-selection-background-color-default: rgba(150, 150, 180, 0.1);
|
||||
--xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);
|
||||
}
|
||||
|
||||
.xy-flow.dark {
|
||||
--xy-node-color-default: #f8f8f8;
|
||||
}
|
||||
|
||||
.xy-flow__handle {
|
||||
background-color: var(--handle-background-color, var(--handle-background-color-default));
|
||||
background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
|
||||
}
|
||||
|
||||
.xy-flow__node-input,
|
||||
.xy-flow__node-default,
|
||||
.xy-flow__node-output,
|
||||
.xy-flow__node-group {
|
||||
border: var(--node-border, var(--node-border-default));
|
||||
border: var(--xy-node-border, var(--xy-node-border-default));
|
||||
color: var(--xy-node-color, var(--xy-node-color-default));
|
||||
|
||||
&.selected,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
border: var(--node-border-selected, var(--node-border-selected-default));
|
||||
border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));
|
||||
}
|
||||
}
|
||||
|
||||
.xy-flow__nodesselection-rect,
|
||||
.xy-flow__selection {
|
||||
background: var(--selection-background-color, var(--selection-background-color-default));
|
||||
border: var(--selection-border, var(--selection-border-default));
|
||||
background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
|
||||
border: var(--xy-selection-border, var(--xy-selection-border-default));
|
||||
}
|
||||
|
||||
@@ -1,20 +1,55 @@
|
||||
/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */
|
||||
|
||||
.xy-flow {
|
||||
--edge-stroke-default: #b1b1b7;
|
||||
--edge-stroke-width-default: 1;
|
||||
--edge-stroke-selected-default: #555;
|
||||
--xy-edge-stroke-default: #b1b1b7;
|
||||
--xy-edge-stroke-width-default: 1;
|
||||
--xy-edge-stroke-selected-default: #555;
|
||||
|
||||
--connectionline-stroke-default: #b1b1b7;
|
||||
--connectionline-stroke-width-default: 1;
|
||||
--xy-connectionline-stroke-default: #b1b1b7;
|
||||
--xy-connectionline-stroke-width-default: 1;
|
||||
|
||||
--attribution-background-color-default: rgba(255, 255, 255, 0.5);
|
||||
--xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);
|
||||
|
||||
--minimap-background-color-default: #fff;
|
||||
--xy-minimap-background-color-default: #fff;
|
||||
--xy-minimap-mask-background-color-default: rgb(240, 240, 240, 0.6);
|
||||
--xy-minimap-node-background-color-default: #e2e2e2;
|
||||
--xy-minimap-node-stroke-color-default: transparent;
|
||||
--xy-minimap-node-stroke-width-default: 2;
|
||||
|
||||
--background-pattern-dot-color-default: #91919a;
|
||||
--background-pattern-line-color-default: #eee;
|
||||
--background-pattern-cross-color-default: #e2e2e2;
|
||||
--xy-background-color-default: transparent;
|
||||
--xy-background-pattern-dots-color-default: #91919a;
|
||||
--xy-background-pattern-lines-color-default: #eee;
|
||||
--xy-background-pattern-cross-color-default: #e2e2e2;
|
||||
}
|
||||
|
||||
.xy-flow.dark {
|
||||
--xy-edge-stroke-default: #3e3e3e;
|
||||
--xy-edge-stroke-width-default: 1;
|
||||
--xy-edge-stroke-selected-default: #727272;
|
||||
|
||||
--xy-connectionline-stroke-default: #b1b1b7;
|
||||
--xy-connectionline-stroke-width-default: 1;
|
||||
|
||||
--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-node-background-color-default: #2b2b2b;
|
||||
--xy-minimap-node-stroke-color-default: transparent;
|
||||
--xy-minimap-node-stroke-width-default: 2;
|
||||
|
||||
--xy-background-color-default: #141414;
|
||||
--xy-background-pattern-dots-color-default: #777;
|
||||
--xy-background-pattern-lines-color-default: #777;
|
||||
--xy-background-pattern-cross-color-default: #777;
|
||||
}
|
||||
|
||||
.xy-flow {
|
||||
background-color: var(--xy-background-color, var(--xy-background-color-default));
|
||||
}
|
||||
|
||||
.xy-flow__background {
|
||||
background-color: var(--xy-background-color, var(--xy-background-color-props, var(--xy-background-color-default)));
|
||||
}
|
||||
|
||||
.xy-flow__container {
|
||||
@@ -58,14 +93,14 @@
|
||||
}
|
||||
|
||||
.xy-flow__edge-path {
|
||||
stroke: var(--edge-stroke, var(--edge-stroke-default));
|
||||
stroke-width: var(--edge-stroke-width, var(--edge-stroke-width-default));
|
||||
stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
|
||||
stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.xy-flow__connection-path {
|
||||
stroke: var(--connectionline-stroke, var(--connectionline-stroke-default));
|
||||
stroke-width: var(--connectionline-stroke-width, var(--connectionline-stroke-width-default));
|
||||
stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));
|
||||
stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));
|
||||
fill: none;
|
||||
}
|
||||
|
||||
@@ -96,23 +131,18 @@
|
||||
&.selected .xy-flow__edge-path,
|
||||
&:focus .xy-flow__edge-path,
|
||||
&:focus-visible .xy-flow__edge-path {
|
||||
stroke: var(--edge-stroke-selected, var(--edge-stroke-selected-default));
|
||||
stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
|
||||
}
|
||||
|
||||
&-textwrapper {
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&-textbg {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.xy-flow__edge-text {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.xy-flow__connection {
|
||||
pointer-events: none;
|
||||
|
||||
@@ -235,7 +265,7 @@
|
||||
|
||||
.xy-flow__attribution {
|
||||
font-size: 10px;
|
||||
background: var(--attribution-background-color, var(--attribution-background-color-default));
|
||||
background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));
|
||||
padding: 2px 3px;
|
||||
margin: 0;
|
||||
|
||||
@@ -262,34 +292,55 @@
|
||||
}
|
||||
|
||||
.xy-flow__minimap {
|
||||
background: var(--minimap-background-color, var(--minimap-background-color-default));
|
||||
background: var(--xy-minimap-background-color, var(--xy-minimap-background-color-default));
|
||||
|
||||
&-mask {
|
||||
fill: var(
|
||||
--xy-minimap-mask-background-color-props,
|
||||
var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))
|
||||
);
|
||||
}
|
||||
|
||||
&-node {
|
||||
fill: var(
|
||||
--xy-minimap-node-background-color-props,
|
||||
var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))
|
||||
);
|
||||
stroke: var(
|
||||
--xy-minimap-node-stroke-color-props,
|
||||
var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))
|
||||
);
|
||||
stroke-width: var(
|
||||
--xy-minimap-node-stroke-width-props,
|
||||
var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.xy-flow__background {
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
background-color: var(--background-color-props, 'transparent');
|
||||
}
|
||||
|
||||
.xy-flow__background-pattern {
|
||||
&.dots {
|
||||
fill: var(
|
||||
--background-pattern-color-props,
|
||||
var(--background-pattern-color, var(--background-pattern-dot-color-default))
|
||||
--xy-background-pattern-color-props,
|
||||
var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))
|
||||
);
|
||||
}
|
||||
|
||||
&.lines {
|
||||
stroke: var(
|
||||
--background-pattern-color-props,
|
||||
var(--background-pattern-color, var(--background-pattern-line-color-default))
|
||||
--xy-background-pattern-color-props,
|
||||
var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))
|
||||
);
|
||||
}
|
||||
|
||||
&.cross {
|
||||
stroke: var(
|
||||
--background-pattern-color-props,
|
||||
var(--background-pattern-color, var(--background-pattern-cross-color-default))
|
||||
--xy-background-pattern-color-props,
|
||||
var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -307,6 +358,7 @@
|
||||
width: 100%;
|
||||
max-width: 12px;
|
||||
max-height: 12px;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,46 @@
|
||||
.xy-flow {
|
||||
--node-color-default: inherit;
|
||||
--node-border-default: 1px solid #1a192b;
|
||||
--node-background-color-default: #fff;
|
||||
--node-group-background-color-default: rgba(240, 240, 240, 0.25);
|
||||
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
|
||||
--node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
|
||||
--xy-node-color-default: inherit;
|
||||
--xy-node-border-default: 1px solid #1a192b;
|
||||
--xy-node-background-color-default: #fff;
|
||||
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
|
||||
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
|
||||
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
|
||||
--xy-node-border-radius-default: 3px;
|
||||
|
||||
--handle-background-color-default: #1a192b;
|
||||
--handle-border-color-default: #fff;
|
||||
--xy-handle-background-color-default: #1a192b;
|
||||
--xy-handle-border-color-default: #fff;
|
||||
|
||||
--selection-background-color-default: rgba(0, 89, 220, 0.08);
|
||||
--selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
|
||||
--xy-selection-background-color-default: rgba(0, 89, 220, 0.08);
|
||||
--xy-selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
|
||||
|
||||
--controls-button-background-color-default: #fefefe;
|
||||
--controls-button-background-color-hover-default: #f4f4f4;
|
||||
--controls-button-color-default: inherit;
|
||||
--controls-button-color-hover-default: inherit;
|
||||
--controls-button-border-color-default: #eee;
|
||||
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
--xy-controls-button-background-color-default: #fefefe;
|
||||
--xy-controls-button-background-color-hover-default: #f4f4f4;
|
||||
--xy-controls-button-color-default: inherit;
|
||||
--xy-controls-button-color-hover-default: inherit;
|
||||
--xy-controls-button-border-color-default: #eee;
|
||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.xy-flow.dark {
|
||||
--xy-node-color-default: #f8f8f8;
|
||||
--xy-node-border-default: 1px solid #3c3c3c;
|
||||
--xy-node-background-color-default: #1e1e1e;
|
||||
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
|
||||
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
|
||||
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #999;
|
||||
|
||||
--xy-handle-background-color-default: #bebebe;
|
||||
--xy-handle-border-color-default: #1e1e1e;
|
||||
|
||||
--xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
|
||||
--xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
|
||||
|
||||
--xy-controls-button-background-color-default: #2b2b2b;
|
||||
--xy-controls-button-background-color-hover-default: #3e3e3e;
|
||||
--xy-controls-button-color-default: #f8f8f8;
|
||||
--xy-controls-button-color-hover-default: #fff;
|
||||
--xy-controls-button-border-color-default: #5b5b5b;
|
||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.xy-flow__edges svg {
|
||||
@@ -50,35 +73,35 @@
|
||||
.xy-flow__node-output,
|
||||
.xy-flow__node-group {
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
border-radius: var(--xy-node-border-radius, var(--xy-node-border-radius-default));
|
||||
width: 150px;
|
||||
font-size: 12px;
|
||||
color: var(--node-color, var(--node-color-default));
|
||||
color: var(--xy-node-color, var(--xy-node-color-default));
|
||||
text-align: center;
|
||||
border: var(--node-border, var(--node-border-default));
|
||||
background-color: var(--node-background-color, var(--node-background-color-default));
|
||||
border: var(--xy-node-border, var(--xy-node-border-default));
|
||||
background-color: var(--xy-node-background-color, var(--xy-node-background-color-default));
|
||||
|
||||
&.selectable {
|
||||
&:hover {
|
||||
box-shadow: var(--node-boxshadow-hover, var(--node-boxshadow-hover-default));
|
||||
box-shadow: var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default));
|
||||
}
|
||||
|
||||
&.selected,
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
box-shadow: var(--node-boxshadow-selected, var(--node-boxshadow-selected-default));
|
||||
box-shadow: var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.xy-flow__node-group {
|
||||
background-color: var(--node-group-background-color, var(--node-group-background-color-default));
|
||||
background-color: var(--xy-node-group-background-color, var(--xy-node-group-background-color-default));
|
||||
}
|
||||
|
||||
.xy-flow__nodesselection-rect,
|
||||
.xy-flow__selection {
|
||||
background: var(--selection-background-color, var(--selection-background-color-default));
|
||||
border: var(--selection-border, var(--selection-border-default));
|
||||
background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
|
||||
border: var(--xy-selection-border, var(--xy-selection-border-default));
|
||||
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
@@ -89,34 +112,37 @@
|
||||
.xy-flow__handle {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: var(--handle-background-color, var(--handle-background-color-default));
|
||||
border: 1px solid var(--handle-border-color, var(--handle-border-color-default));
|
||||
background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
|
||||
border: 1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.xy-flow__controls {
|
||||
box-shadow: var(--controls-box-shadow, var(--controls-box-shadow-default));
|
||||
box-shadow: var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default));
|
||||
|
||||
&-button {
|
||||
border: none;
|
||||
background: var(--controls-button-background-color, var(--controls-button-background-color-default));
|
||||
background: var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));
|
||||
border-bottom: 1px solid
|
||||
var(
|
||||
--controls-button-border-color-props,
|
||||
var(--controls-button-border-color, var(--controls-button-border-color-default))
|
||||
--xy-controls-button-border-color-props,
|
||||
var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default))
|
||||
);
|
||||
color: var(--controls-button-color-props, var(--controls-button-color, var(--controls-button-color-default)));
|
||||
color: var(
|
||||
--xy-controls-button-color-props,
|
||||
var(--xy-controls-button-color, var(--xy-controls-button-color-default))
|
||||
);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background: var(
|
||||
--controls-button-background-color-hover-props,
|
||||
var(--controls-button-background-color-hover, var(--controls-button-background-color-hover-default))
|
||||
--xy-controls-button-background-color-hover-props,
|
||||
var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default))
|
||||
);
|
||||
color: var(
|
||||
--controls-button-color-hover-props,
|
||||
var(--controls-button-hover-color, var(--controls-button-hover-color-default))
|
||||
--xy-controls-button-color-hover-props,
|
||||
var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -128,4 +154,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-button:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ export type SmoothStepPathOptions = {
|
||||
borderRadius?: number;
|
||||
};
|
||||
|
||||
export type StepPathOptions = {
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
export type BezierPathOptions = {
|
||||
curvature?: number;
|
||||
};
|
||||
|
||||
@@ -22,8 +22,8 @@ export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => vo
|
||||
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
|
||||
|
||||
export type Connection = {
|
||||
source: string | null;
|
||||
target: string | null;
|
||||
source: string;
|
||||
target: string;
|
||||
sourceHandle: string | null;
|
||||
targetHandle: string | null;
|
||||
};
|
||||
@@ -136,3 +136,8 @@ export type UpdateConnection = (params: {
|
||||
connectionStartHandle: ConnectingHandle | null;
|
||||
connectionEndHandle: ConnectingHandle | null;
|
||||
}) => void;
|
||||
|
||||
export type ColorModeClass = 'light' | 'dark';
|
||||
export type ColorMode = ColorModeClass | 'system';
|
||||
|
||||
export type ConnectionLookup = Map<string, Map<string, Connection>>;
|
||||
|
||||
@@ -25,14 +25,14 @@ export type NodeBase<T = any, U extends string | undefined = string | undefined>
|
||||
zIndex?: number;
|
||||
extent?: 'parent' | CoordinateExtent;
|
||||
expandParent?: boolean;
|
||||
positionAbsolute?: XYPosition;
|
||||
ariaLabel?: string;
|
||||
focusable?: boolean;
|
||||
origin?: NodeOrigin;
|
||||
handles?: NodeHandle[];
|
||||
size?: {
|
||||
computed?: {
|
||||
width?: number;
|
||||
height?: number;
|
||||
positionAbsolute?: XYPosition;
|
||||
};
|
||||
|
||||
// only used internally
|
||||
@@ -40,6 +40,10 @@ export type NodeBase<T = any, U extends string | undefined = string | undefined>
|
||||
z?: number;
|
||||
handleBounds?: NodeHandleBounds;
|
||||
isParent?: boolean;
|
||||
/** Holds a reference to the original node object provided by the user
|
||||
* (which may lack some fields, like `computed` or `[internalSymbol]`. Used
|
||||
* as an optimization to avoid certain operations. */
|
||||
userProvidedNode: NodeBase<T, U>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -52,8 +56,10 @@ export type NodeProps<T = any> = {
|
||||
selected: NodeBase['selected'];
|
||||
isConnectable: NodeBase['connectable'];
|
||||
zIndex: NodeBase['zIndex'];
|
||||
xPos: number;
|
||||
yPos: number;
|
||||
positionAbsoluteX: number;
|
||||
positionAbsoluteY: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
dragging: boolean;
|
||||
targetPosition?: Position;
|
||||
sourcePosition?: Position;
|
||||
@@ -78,11 +84,13 @@ export type NodeBounds = XYPosition & {
|
||||
export type NodeDragItem = {
|
||||
id: string;
|
||||
position: XYPosition;
|
||||
positionAbsolute: XYPosition;
|
||||
// distance from the mouse cursor to the node when start dragging
|
||||
distance: XYPosition;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
computed: {
|
||||
width: number | null;
|
||||
height: number | null;
|
||||
positionAbsolute: XYPosition;
|
||||
};
|
||||
extent?: 'parent' | CoordinateExtent;
|
||||
parentNode?: string;
|
||||
dragging?: boolean;
|
||||
@@ -97,3 +105,5 @@ export type OnNodeDrag = (event: MouseEvent, node: NodeBase, nodes: NodeBase[])
|
||||
export type OnSelectionDrag = (event: MouseEvent, nodes: NodeBase[]) => void;
|
||||
|
||||
export type NodeHandle = Optional<HandleElement, 'width' | 'height'>;
|
||||
|
||||
export type Align = 'center' | 'start' | 'end';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { Optional } from '../utils/types';
|
||||
|
||||
export enum Position {
|
||||
Left = 'left',
|
||||
Top = 'top',
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Connection } from '../types';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function areConnectionMapsEqual(a?: Map<string, Connection>, b?: Map<string, Connection>) {
|
||||
if (!a && !b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!a || !b || a.size !== b.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a.size && !b.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const key of a.keys()) {
|
||||
if (!b.has(key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* We call the callback for all connections in a that are not in b
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function handleConnectionChange(
|
||||
a: Map<string, Connection>,
|
||||
b: Map<string, Connection>,
|
||||
cb?: (diff: Connection[]) => void
|
||||
) {
|
||||
if (!cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
const diff: Connection[] = [];
|
||||
|
||||
a.forEach((connection, key) => {
|
||||
if (!b?.has(key)) {
|
||||
diff.push(connection);
|
||||
}
|
||||
});
|
||||
|
||||
if (diff.length) {
|
||||
cb(diff);
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@ export const getHandleBounds = (
|
||||
}
|
||||
|
||||
const handlesArray = Array.from(handles) as HTMLDivElement[];
|
||||
|
||||
// @todo can't we use the node dimensions here?
|
||||
const nodeBounds = nodeElement.getBoundingClientRect();
|
||||
const nodeOffset = {
|
||||
x: nodeBounds.width * nodeOrigin[0],
|
||||
|
||||
@@ -75,7 +75,7 @@ export function isEdgeVisible({ sourceNode, targetNode, width, height, transform
|
||||
}
|
||||
|
||||
const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection | EdgeBase): string =>
|
||||
`xyflow__edge-${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;
|
||||
`xy-edge__${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;
|
||||
|
||||
const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => {
|
||||
return edges.some(
|
||||
@@ -111,6 +111,14 @@ export const addEdgeBase = <EdgeType extends EdgeBase>(
|
||||
return edges;
|
||||
}
|
||||
|
||||
if (edge.sourceHandle === null) {
|
||||
delete edge.sourceHandle;
|
||||
}
|
||||
|
||||
if (edge.targetHandle === null) {
|
||||
delete edge.targetHandle;
|
||||
}
|
||||
|
||||
return edges.concat(edge);
|
||||
};
|
||||
|
||||
|
||||
@@ -88,20 +88,20 @@ function toHandleBounds(handles?: NodeHandle[]) {
|
||||
|
||||
function getHandleDataByNode(node?: NodeBase): [Rect, NodeHandleBounds | null, boolean] {
|
||||
const handleBounds = node?.[internalsSymbol]?.handleBounds || toHandleBounds(node?.handles) || null;
|
||||
const nodeWidth = node?.width || node?.size?.width;
|
||||
const nodeHeight = node?.height || node?.size?.height;
|
||||
const nodeWidth = node?.computed?.width || node?.width;
|
||||
const nodeHeight = node?.computed?.height || node?.height;
|
||||
|
||||
const isValid =
|
||||
handleBounds &&
|
||||
nodeWidth &&
|
||||
nodeHeight &&
|
||||
typeof node?.positionAbsolute?.x !== 'undefined' &&
|
||||
typeof node?.positionAbsolute?.y !== 'undefined';
|
||||
typeof node?.computed?.positionAbsolute?.x !== 'undefined' &&
|
||||
typeof node?.computed?.positionAbsolute?.y !== 'undefined';
|
||||
|
||||
return [
|
||||
{
|
||||
x: node?.positionAbsolute?.x || 0,
|
||||
y: node?.positionAbsolute?.y || 0,
|
||||
x: node?.computed?.positionAbsolute?.x || 0,
|
||||
y: node?.computed?.positionAbsolute?.y || 0,
|
||||
width: nodeWidth || 0,
|
||||
height: nodeHeight || 0,
|
||||
},
|
||||
|
||||
@@ -64,8 +64,8 @@ export const nodeToRect = (node: NodeBase, nodeOrigin: NodeOrigin = [0, 0]): Rec
|
||||
|
||||
return {
|
||||
...positionAbsolute,
|
||||
width: node.width || 0,
|
||||
height: node.height || 0,
|
||||
width: node.computed?.width ?? node.width ?? 0,
|
||||
height: node.computed?.height ?? node.height ?? 0,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -74,8 +74,8 @@ export const nodeToBox = (node: NodeBase, nodeOrigin: NodeOrigin = [0, 0]): Box
|
||||
|
||||
return {
|
||||
...positionAbsolute,
|
||||
x2: positionAbsolute.x + (node.width || 0),
|
||||
y2: positionAbsolute.y + (node.height || 0),
|
||||
x2: positionAbsolute.x + (node.computed?.width ?? node.width ?? 0),
|
||||
y2: positionAbsolute.y + (node.computed?.height ?? node.height ?? 0),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
getViewportForBounds,
|
||||
} from './general';
|
||||
import {
|
||||
type Connection,
|
||||
type Transform,
|
||||
type XYPosition,
|
||||
type Rect,
|
||||
@@ -26,13 +25,11 @@ import {
|
||||
} from '../types';
|
||||
import { errorMessages } from '../constants';
|
||||
|
||||
export const isEdgeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||
element: NodeType | Connection | EdgeType
|
||||
): element is EdgeType => 'id' in element && 'source' in element && 'target' in element;
|
||||
export const isEdgeBase = <EdgeType extends EdgeBase = EdgeBase>(element: any): element is EdgeType =>
|
||||
'id' in element && 'source' in element && 'target' in element;
|
||||
|
||||
export const isNodeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||
element: NodeType | Connection | EdgeType
|
||||
): element is NodeType => 'id' in element && !('source' in element) && !('target' in element);
|
||||
export const isNodeBase = <NodeType extends NodeBase = NodeBase>(element: any): element is NodeType =>
|
||||
'id' in element && !('source' in element) && !('target' in element);
|
||||
|
||||
export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||
node: NodeType | { id: string },
|
||||
@@ -86,8 +83,8 @@ export const getNodePositionWithOrigin = (
|
||||
};
|
||||
}
|
||||
|
||||
const offsetX = (node.width ?? 0) * nodeOrigin[0];
|
||||
const offsetY = (node.height ?? 0) * nodeOrigin[1];
|
||||
const offsetX = (node.computed?.width ?? node.width ?? 0) * nodeOrigin[0];
|
||||
const offsetY = (node.computed?.height ?? node.height ?? 0) * nodeOrigin[1];
|
||||
|
||||
const position: XYPosition = {
|
||||
x: node.position.x - offsetX,
|
||||
@@ -96,10 +93,10 @@ export const getNodePositionWithOrigin = (
|
||||
|
||||
return {
|
||||
...position,
|
||||
positionAbsolute: node.positionAbsolute
|
||||
positionAbsolute: node.computed?.positionAbsolute
|
||||
? {
|
||||
x: node.positionAbsolute.x - offsetX,
|
||||
y: node.positionAbsolute.y - offsetY,
|
||||
x: node.computed.positionAbsolute.x - offsetX,
|
||||
y: node.computed.positionAbsolute.y - offsetY,
|
||||
}
|
||||
: position,
|
||||
};
|
||||
@@ -118,8 +115,8 @@ export const getNodesBounds = (nodes: NodeBase[], nodeOrigin: NodeOrigin = [0, 0
|
||||
rectToBox({
|
||||
x,
|
||||
y,
|
||||
width: node.width || 0,
|
||||
height: node.height || 0,
|
||||
width: node.computed?.width ?? node.width ?? 0,
|
||||
height: node.computed?.height ?? node.height ?? 0,
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -145,17 +142,19 @@ export const getNodesInside = <NodeType extends NodeBase>(
|
||||
};
|
||||
|
||||
const visibleNodes = nodes.reduce<NodeType[]>((res, node) => {
|
||||
const { width, height, selectable = true, hidden = false } = node;
|
||||
const { computed, selectable = true, hidden = false } = node;
|
||||
const width = computed?.width ?? node.width ?? null;
|
||||
const height = computed?.height ?? node.height ?? null;
|
||||
|
||||
if ((excludeNonSelectableNodes && !selectable) || hidden) {
|
||||
return res;
|
||||
}
|
||||
|
||||
const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node, nodeOrigin));
|
||||
const notInitialized = width === undefined || height === undefined || width === null || height === null;
|
||||
const notInitialized = width === null || height === null;
|
||||
|
||||
const partiallyVisible = partially && overlappingArea > 0;
|
||||
const area = (width || 0) * (height || 0);
|
||||
const area = (width ?? 0) * (height ?? 0);
|
||||
const isVisible = notInitialized || partiallyVisible || overlappingArea >= area;
|
||||
|
||||
if (isVisible || node.dragging) {
|
||||
@@ -185,7 +184,7 @@ export function fitView<Params extends FitViewParamsBase<NodeBase>, Options exte
|
||||
options?: Options
|
||||
) {
|
||||
const filteredNodes = nodes.filter((n) => {
|
||||
const isVisible = n.width && n.height && (options?.includeHiddenNodes || !n.hidden);
|
||||
const isVisible = n.computed?.width && n.computed?.height && (options?.includeHiddenNodes || !n.hidden);
|
||||
|
||||
if (options?.nodes?.length) {
|
||||
return isVisible && options?.nodes.some((optionNode) => optionNode.id === n.id);
|
||||
@@ -218,7 +217,7 @@ function clampNodeExtent(node: NodeDragItem | NodeBase, extent?: CoordinateExten
|
||||
if (!extent || extent === 'parent') {
|
||||
return extent;
|
||||
}
|
||||
return [extent[0], [extent[1][0] - (node.width || 0), extent[1][1] - (node.height || 0)]];
|
||||
return [extent[0], [extent[1][0] - (node.computed?.width ?? 0), extent[1][1] - (node.computed?.height ?? 0)]];
|
||||
}
|
||||
|
||||
export function calcNextPosition<NodeType extends NodeBase>(
|
||||
@@ -242,16 +241,18 @@ export function calcNextPosition<NodeType extends NodeBase>(
|
||||
}
|
||||
|
||||
if (node.extent === 'parent' && !node.expandParent) {
|
||||
if (node.parentNode && node.width && node.height) {
|
||||
const nodeWidth = node.computed?.width;
|
||||
const nodeHeight = node.computed?.height;
|
||||
if (node.parentNode && nodeWidth && nodeHeight) {
|
||||
const currNodeOrigin = node.origin || nodeOrigin;
|
||||
|
||||
currentExtent =
|
||||
parentNode && isNumeric(parentNode.width) && isNumeric(parentNode.height)
|
||||
parentNode && isNumeric(parentNode.computed?.width) && isNumeric(parentNode.computed?.height)
|
||||
? [
|
||||
[parentPos.x + node.width * currNodeOrigin[0], parentPos.y + node.height * currNodeOrigin[1]],
|
||||
[parentPos.x + nodeWidth * currNodeOrigin[0], parentPos.y + nodeHeight * currNodeOrigin[1]],
|
||||
[
|
||||
parentPos.x + parentNode.width - node.width + node.width * currNodeOrigin[0],
|
||||
parentPos.y + parentNode.height - node.height + node.height * currNodeOrigin[1],
|
||||
parentPos.x + (parentNode.computed?.width ?? 0) - nodeWidth + nodeWidth * currNodeOrigin[0],
|
||||
parentPos.y + (parentNode.computed?.height ?? 0) - nodeHeight + nodeHeight * currNodeOrigin[1],
|
||||
],
|
||||
]
|
||||
: currentExtent;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
export * from './connections';
|
||||
export * from './dom';
|
||||
export * from './edges';
|
||||
export * from './graph';
|
||||
export * from './general';
|
||||
export * from './marker';
|
||||
export * from './node-toolbar';
|
||||
export * from './store';
|
||||
export * from './types';
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Position, type Rect, type Viewport, type Align } from '../';
|
||||
|
||||
export function getNodeToolbarTransform(
|
||||
nodeRect: Rect,
|
||||
viewport: Viewport,
|
||||
position: Position,
|
||||
offset: number,
|
||||
align: Align
|
||||
): string {
|
||||
let alignmentOffset = 0.5;
|
||||
|
||||
if (align === 'start') {
|
||||
alignmentOffset = 0;
|
||||
} else if (align === 'end') {
|
||||
alignmentOffset = 1;
|
||||
}
|
||||
|
||||
// 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,
|
||||
];
|
||||
// and than shift it based on the alignment. The shift values are in %.
|
||||
let shift = [-100 * alignmentOffset, -100];
|
||||
|
||||
switch (position) {
|
||||
case Position.Right:
|
||||
pos = [
|
||||
(nodeRect.x + nodeRect.width) * viewport.zoom + viewport.x + offset,
|
||||
(nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y,
|
||||
];
|
||||
shift = [0, -100 * alignmentOffset];
|
||||
break;
|
||||
case Position.Bottom:
|
||||
pos[1] = (nodeRect.y + nodeRect.height) * viewport.zoom + viewport.y + offset;
|
||||
shift[1] = 0;
|
||||
break;
|
||||
case Position.Left:
|
||||
pos = [
|
||||
nodeRect.x * viewport.zoom + viewport.x - offset,
|
||||
(nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y,
|
||||
];
|
||||
shift = [-100, -100 * alignmentOffset];
|
||||
break;
|
||||
}
|
||||
|
||||
return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
Transform,
|
||||
XYPosition,
|
||||
XYZPosition,
|
||||
ConnectionLookup,
|
||||
EdgeBase,
|
||||
} from '../types';
|
||||
import { getDimensions, getHandleBounds } from './dom';
|
||||
import { isNumeric } from './general';
|
||||
@@ -40,7 +42,7 @@ export function updateAbsolutePositions<NodeType extends NodeBase>(
|
||||
parentNode?.origin || nodeOrigin
|
||||
);
|
||||
|
||||
node.positionAbsolute = {
|
||||
node.computed!.positionAbsolute = {
|
||||
x,
|
||||
y,
|
||||
};
|
||||
@@ -62,7 +64,7 @@ type UpdateNodesOptions<NodeType extends NodeBase> = {
|
||||
defaults?: Partial<NodeType>;
|
||||
};
|
||||
|
||||
export function updateNodes<NodeType extends NodeBase>(
|
||||
export function adoptUserProvidedNodes<NodeType extends NodeBase>(
|
||||
nodes: NodeType[],
|
||||
nodeLookup: Map<string, NodeType>,
|
||||
options: UpdateNodesOptions<NodeType> = {
|
||||
@@ -71,17 +73,26 @@ export function updateNodes<NodeType extends NodeBase>(
|
||||
defaults: {},
|
||||
}
|
||||
): NodeType[] {
|
||||
const tmpLookup = new Map(nodeLookup);
|
||||
nodeLookup.clear();
|
||||
const parentNodes: ParentNodes = {};
|
||||
const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0;
|
||||
|
||||
const nextNodes = nodes.map((n) => {
|
||||
const currentStoreNode = nodeLookup.get(n.id);
|
||||
const currentStoreNode = tmpLookup.get(n.id);
|
||||
if (n === currentStoreNode?.[internalsSymbol]?.userProvidedNode) {
|
||||
nodeLookup.set(n.id, currentStoreNode);
|
||||
return currentStoreNode;
|
||||
}
|
||||
|
||||
const node: NodeType = {
|
||||
...options.defaults,
|
||||
...n,
|
||||
positionAbsolute: n.position,
|
||||
width: n.width || currentStoreNode?.width,
|
||||
height: n.height || currentStoreNode?.height,
|
||||
computed: {
|
||||
positionAbsolute: n.position,
|
||||
width: n.computed?.width || currentStoreNode?.computed?.width,
|
||||
height: n.computed?.height || currentStoreNode?.computed?.height,
|
||||
},
|
||||
};
|
||||
const z = (isNumeric(n.zIndex) ? n.zIndex : 0) + (n.selected ? selectedNodeZ : 0);
|
||||
const currInternals = n?.[internalsSymbol] || currentStoreNode?.[internalsSymbol];
|
||||
@@ -95,6 +106,7 @@ export function updateNodes<NodeType extends NodeBase>(
|
||||
value: {
|
||||
handleBounds: currInternals?.handleBounds,
|
||||
z,
|
||||
userProvidedNode: n,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -135,14 +147,14 @@ function calculateXYZPosition<NodeType extends NodeBase>(
|
||||
);
|
||||
}
|
||||
|
||||
export function updateNodeDimensions(
|
||||
export function updateNodeDimensions<NodeType extends NodeBase>(
|
||||
updates: Map<string, NodeDimensionUpdate>,
|
||||
nodes: NodeBase[],
|
||||
nodeLookup: Map<string, NodeBase>,
|
||||
nodes: NodeType[],
|
||||
nodeLookup: Map<string, NodeType>,
|
||||
domNode: HTMLElement | null,
|
||||
nodeOrigin?: NodeOrigin,
|
||||
onUpdate?: (id: string, dimensions: Dimensions) => void
|
||||
): NodeBase[] | null {
|
||||
): NodeType[] | null {
|
||||
const viewportNode = domNode?.querySelector('.xyflow__viewport');
|
||||
|
||||
if (!viewportNode) {
|
||||
@@ -160,7 +172,7 @@ export function updateNodeDimensions(
|
||||
const doUpdate = !!(
|
||||
dimensions.width &&
|
||||
dimensions.height &&
|
||||
(node.width !== dimensions.width || node.height !== dimensions.height || update.forceUpdate)
|
||||
(node.computed?.width !== dimensions.width || node.computed?.height !== dimensions.height || update.forceUpdate)
|
||||
);
|
||||
|
||||
if (doUpdate) {
|
||||
@@ -168,7 +180,10 @@ export function updateNodeDimensions(
|
||||
|
||||
const newNode = {
|
||||
...node,
|
||||
...dimensions,
|
||||
computed: {
|
||||
...node.computed,
|
||||
...dimensions,
|
||||
},
|
||||
[internalsSymbol]: {
|
||||
...node[internalsSymbol],
|
||||
handleBounds: {
|
||||
@@ -228,3 +243,23 @@ export function panBy({
|
||||
|
||||
return transformChanged;
|
||||
}
|
||||
|
||||
export function updateConnectionLookup(lookup: ConnectionLookup, edges: EdgeBase[]) {
|
||||
lookup.clear();
|
||||
|
||||
edges.forEach(({ source, target, sourceHandle = null, targetHandle = null }) => {
|
||||
if (source && target) {
|
||||
const sourceKey = `${source}-source-${sourceHandle}`;
|
||||
const targetKey = `${target}-target-${targetHandle}`;
|
||||
|
||||
const prevSource = lookup.get(sourceKey) || new Map();
|
||||
const prevTarget = lookup.get(targetKey) || new Map();
|
||||
const connection = { source, target, sourceHandle, targetHandle };
|
||||
|
||||
lookup.set(sourceKey, prevSource.set(`${target}-${targetHandle}`, connection));
|
||||
lookup.set(targetKey, prevTarget.set(`${source}-${sourceHandle}`, connection));
|
||||
}
|
||||
});
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
@@ -140,11 +140,13 @@ export function XYDrag({
|
||||
];
|
||||
|
||||
if (dragItems.length > 1 && nodeExtent && !n.extent) {
|
||||
adjustedNodeExtent[0][0] = n.positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
||||
adjustedNodeExtent[1][0] = n.positionAbsolute.x + (n.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
|
||||
adjustedNodeExtent[0][0] = n.computed.positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
|
||||
adjustedNodeExtent[1][0] =
|
||||
n.computed.positionAbsolute.x + (n.computed?.width ?? 0) - nodesBox.x2 + nodeExtent[1][0];
|
||||
|
||||
adjustedNodeExtent[0][1] = n.positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
||||
adjustedNodeExtent[1][1] = n.positionAbsolute.y + (n.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
|
||||
adjustedNodeExtent[0][1] = n.computed.positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
|
||||
adjustedNodeExtent[1][1] =
|
||||
n.computed.positionAbsolute.y + (n.computed?.height ?? 0) - nodesBox.y2 + nodeExtent[1][1];
|
||||
}
|
||||
|
||||
const updatedPos = calcNextPosition(n, nextPosition, nodes, adjustedNodeExtent, nodeOrigin, onError);
|
||||
@@ -153,7 +155,7 @@ export function XYDrag({
|
||||
hasChange = hasChange || n.position.x !== updatedPos.position.x || n.position.y !== updatedPos.position.y;
|
||||
|
||||
n.position = updatedPos.position;
|
||||
n.positionAbsolute = updatedPos.positionAbsolute;
|
||||
n.computed.positionAbsolute = updatedPos.positionAbsolute;
|
||||
|
||||
return n;
|
||||
});
|
||||
|
||||
@@ -51,10 +51,9 @@ export function getDragItems<NodeType extends NodeBase>(
|
||||
.map((n) => ({
|
||||
id: n.id,
|
||||
position: n.position || { x: 0, y: 0 },
|
||||
positionAbsolute: n.positionAbsolute || { x: 0, y: 0 },
|
||||
distance: {
|
||||
x: mousePos.x - (n.positionAbsolute?.x ?? 0),
|
||||
y: mousePos.y - (n.positionAbsolute?.y ?? 0),
|
||||
x: mousePos.x - (n.computed?.positionAbsolute?.x ?? 0),
|
||||
y: mousePos.y - (n.computed?.positionAbsolute?.y ?? 0),
|
||||
},
|
||||
delta: {
|
||||
x: 0,
|
||||
@@ -62,10 +61,13 @@ export function getDragItems<NodeType extends NodeBase>(
|
||||
},
|
||||
extent: n.extent,
|
||||
parentNode: n.parentNode,
|
||||
width: n.width,
|
||||
height: n.height,
|
||||
origin: n.origin,
|
||||
expandParent: n.expandParent,
|
||||
computed: {
|
||||
positionAbsolute: n.computed?.positionAbsolute || { x: 0, y: 0 },
|
||||
width: n.computed?.width || 0,
|
||||
height: n.computed?.height || 0,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -81,15 +83,18 @@ export function getEventHandlerParams<NodeType extends NodeBase>({
|
||||
dragItems: NodeDragItem[];
|
||||
nodeLookup: Map<string, NodeType>;
|
||||
}): [NodeType, NodeType[]] {
|
||||
const extentedDragItems: NodeType[] = dragItems.map((n) => {
|
||||
const nodesFromDragItems: NodeType[] = dragItems.map((n) => {
|
||||
const node = nodeLookup.get(n.id)!;
|
||||
|
||||
return {
|
||||
...node,
|
||||
position: n.position,
|
||||
positionAbsolute: n.positionAbsolute,
|
||||
computed: {
|
||||
...n.computed,
|
||||
positionAbsolute: n.computed.positionAbsolute,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return [nodeId ? extentedDragItems.find((n) => n.id === nodeId)! : extentedDragItems[0], extentedDragItems];
|
||||
return [nodeId ? nodesFromDragItems.find((n) => n.id === nodeId)! : nodesFromDragItems[0], nodesFromDragItems];
|
||||
}
|
||||
|
||||
@@ -58,12 +58,10 @@ export type XYHandleInstance = {
|
||||
type Result = {
|
||||
handleDomNode: Element | null;
|
||||
isValid: boolean;
|
||||
connection: Connection;
|
||||
connection: Connection | null;
|
||||
endHandle: ConnectingHandle | null;
|
||||
};
|
||||
|
||||
const nullConnection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null };
|
||||
|
||||
const alwaysValid = () => true;
|
||||
|
||||
let connectionStartHandle: ConnectingHandle | null = null;
|
||||
@@ -197,7 +195,7 @@ function onPointerDown(
|
||||
return resetRecentHandle(prevActiveHandle, lib);
|
||||
}
|
||||
|
||||
if (connection.source !== connection.target && handleDomNode) {
|
||||
if (connection?.source !== connection?.target && handleDomNode) {
|
||||
resetRecentHandle(prevActiveHandle, lib);
|
||||
prevActiveHandle = handleDomNode;
|
||||
handleDomNode.classList.add('connecting', `${lib}-flow__handle-connecting`);
|
||||
@@ -269,7 +267,7 @@ function isValidHandle(
|
||||
const result: Result = {
|
||||
handleDomNode: handleToCheck,
|
||||
isValid: false,
|
||||
connection: nullConnection,
|
||||
connection: null,
|
||||
endHandle: null,
|
||||
};
|
||||
|
||||
@@ -280,6 +278,10 @@ function isValidHandle(
|
||||
const connectable = handleToCheck.classList.contains('connectable');
|
||||
const connectableEnd = handleToCheck.classList.contains('connectableend');
|
||||
|
||||
if (!handleNodeId) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const connection: Connection = {
|
||||
source: isTarget ? handleNodeId : fromNodeId,
|
||||
sourceHandle: isTarget ? handleId : fromHandleId,
|
||||
|
||||
@@ -22,8 +22,8 @@ export function getHandles(
|
||||
id: h.id || null,
|
||||
type,
|
||||
nodeId: node.id,
|
||||
x: (node.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
|
||||
y: (node.positionAbsolute?.y ?? 0) + h.y + h.height / 2,
|
||||
x: (node.computed?.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
|
||||
y: (node.computed?.positionAbsolute?.y ?? 0) + h.y + h.height / 2,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user