Merge branch 'main' into perf/noderenderer-minimap

This commit is contained in:
moklick
2023-12-13 16:32:02 +01:00
101 changed files with 2671 additions and 685 deletions
+12 -12
View File
@@ -1,38 +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 {
--node-color-default: #f8f8f8;
--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));
color: var(--node-color, var(--node-color-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));
}
+56 -52
View File
@@ -1,51 +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;
--minimap-mask-background-color-default: rgb(240, 240, 240, 0.6);
--minimap-node-background-color-default: #e2e2e2;
--minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2;
--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-color-default: transparent;
--background-pattern-dots-color-default: #91919a;
--background-pattern-lines-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 {
--edge-stroke-default: #3c3c3c;
--edge-stroke-width-default: 1;
--edge-stroke-selected-default: #727272;
--xy-edge-stroke-default: #3e3e3e;
--xy-edge-stroke-width-default: 1;
--xy-edge-stroke-selected-default: #727272;
--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(150, 150, 150, 0.25);
--xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);
--minimap-background-color-default: #141414;
--minimap-mask-background-color-default: rgb(60, 60, 60, 0.6);
--minimap-node-background-color-default: #2b2b2b;
--minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2;
--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;
--background-color-default: #141414;
--background-pattern-dots-color-default: #777;
--background-pattern-lines-color-default: #777;
--background-pattern-cross-color-default: #777;
--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(--background-color-props, var(--background-color-default, 'transparent'));
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 {
@@ -94,14 +98,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;
}
@@ -132,7 +136,7 @@
&.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 {
@@ -266,7 +270,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;
@@ -293,27 +297,27 @@
}
.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(
--minimap-mask-background-color-props,
var(--minimap-mask-background-color, var(--minimap-mask-background-color-default))
--xy-minimap-mask-background-color-props,
var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))
);
}
&-node {
fill: var(
--minimap-node-background-color-props,
var(--minimap-node-background-color, var(--minimap-node-background-color-default))
--xy-minimap-node-background-color-props,
var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))
);
stroke: var(
--minimap-node-stroke-color-props,
var(--minimap-node-stroke-color, var(--minimap-node-stroke-color-default))
--xy-minimap-node-stroke-color-props,
var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))
);
stroke-width: var(
--minimap-node-stroke-width-props,
var(--minimap-node-stroke-width, var(--minimap-node-stroke-width-default))
--xy-minimap-node-stroke-width-props,
var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))
);
}
}
@@ -326,22 +330,22 @@
.xy-flow__background-pattern {
&.dots {
fill: var(
--background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-dots-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-lines-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))
);
}
}
+56 -53
View File
@@ -1,46 +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;
--node-border-radius-default: 3px;
--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 {
--node-color-default: #f8f8f8;
--node-border-default: 1px solid #3c3c3c;
--node-background-color-default: #1e1e1e;
--node-group-background-color-default: rgba(240, 240, 240, 0.25);
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
--node-boxshadow-selected-default: 0 0 0 0.5px #999;
--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;
--handle-background-color-default: #bebebe;
--handle-border-color-default: #1e1e1e;
--xy-handle-background-color-default: #bebebe;
--xy-handle-border-color-default: #1e1e1e;
--selection-background-color-default: rgba(200, 200, 220, 0.08);
--selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
--xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
--xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
--controls-button-background-color-default: #2b2b2b;
--controls-button-background-color-hover-default: #3e3e3e;
--controls-button-color-default: #f8f8f8;
--controls-button-color-hover-default: #fff;
--controls-button-border-color-default: #5b5b5b;
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
--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__edge {
@@ -67,35 +67,35 @@
.xy-flow__node-output,
.xy-flow__node-group {
padding: 10px;
border-radius: var(--node-border-radius, var(--node-border-radius-default));
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 {
@@ -106,34 +106,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-color-hover, var(--controls-button-color-hover-default))
--xy-controls-button-color-hover-props,
var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default))
);
}
+4
View File
@@ -27,6 +27,10 @@ export type SmoothStepPathOptions = {
borderRadius?: number;
};
export type StepPathOptions = {
offset?: number;
};
export type BezierPathOptions = {
curvature?: number;
};
+4 -2
View File
@@ -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;
};
@@ -139,3 +139,5 @@ export type UpdateConnection = (params: {
export type ColorModeClass = 'light' | 'dark';
export type ColorMode = ColorModeClass | 'system';
export type ConnectionLookup = Map<string, Map<string, Connection>>;
+2
View File
@@ -1,3 +1,5 @@
import type { Optional } from '../utils/types';
export enum Position {
Left = 'left',
Top = 'top',
+53
View File
@@ -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);
}
}
+9 -1
View File
@@ -112,7 +112,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(
@@ -148,6 +148,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);
};
+4 -7
View File
@@ -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 },
+2
View File
@@ -1,3 +1,4 @@
export * from './connections';
export * from './dom';
export * from './edges';
export * from './graph';
@@ -5,3 +6,4 @@ export * from './general';
export * from './marker';
export * from './node-toolbar';
export * from './store';
export * from './types';
+25 -1
View File
@@ -9,6 +9,8 @@ import {
Transform,
XYPosition,
XYZPosition,
ConnectionLookup,
EdgeBase,
} from '../types';
import { getDimensions, getHandleBounds } from './dom';
import { isNumeric } from './general';
@@ -71,11 +73,13 @@ export function adoptUserProvidedNodes<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.deref()) return currentStoreNode;
const node: NodeType = {
@@ -236,3 +240,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;
}
+7 -5
View File
@@ -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,