Merge pull request #3795 from xyflow/next
React Flow 12.0.0-next.7, Svelte Flow 0.0.34
This commit is contained in:
@@ -13,7 +13,8 @@
|
|||||||
type Node,
|
type Node,
|
||||||
type Edge,
|
type Edge,
|
||||||
ConnectionMode,
|
ConnectionMode,
|
||||||
useSvelteFlow
|
useSvelteFlow,
|
||||||
|
ControlButton
|
||||||
} from '@xyflow/svelte';
|
} from '@xyflow/svelte';
|
||||||
|
|
||||||
import CustomNode from './CustomNode.svelte';
|
import CustomNode from './CustomNode.svelte';
|
||||||
@@ -187,7 +188,12 @@
|
|||||||
connectionMode={ConnectionMode.Strict}
|
connectionMode={ConnectionMode.Strict}
|
||||||
attributionPosition={'top-center'}
|
attributionPosition={'top-center'}
|
||||||
>
|
>
|
||||||
<Controls />
|
<Controls>
|
||||||
|
<ControlButton slot="before">xy</ControlButton>
|
||||||
|
<ControlButton aria-label="log" on:click={() => console.log('control button')}
|
||||||
|
>log</ControlButton
|
||||||
|
>
|
||||||
|
</Controls>
|
||||||
<Background variant={BackgroundVariant.Dots} />
|
<Background variant={BackgroundVariant.Dots} />
|
||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Panel position="top-right">
|
<Panel position="top-right">
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# @xyflow/react
|
# @xyflow/react
|
||||||
|
|
||||||
|
## 12.0.0-next.7
|
||||||
|
|
||||||
|
## Minor changes
|
||||||
|
|
||||||
|
- pass Node/Edge types to changes thanks @FelipeEmos
|
||||||
|
- use position instead of positionAbsolute for `getNodesBounds`
|
||||||
|
- add second option param to `screenToFlowPosition` for configuring if `snapToGrid` should be used
|
||||||
|
- infer types for `getIncomers`, `getOutgoers`, `updateEdge`, `addEdge` and `getConnectedEdges` thanks @joeyballentine
|
||||||
|
- refactor handles: prefix with flow id for handling nested flows
|
||||||
|
- add comments for types like `ReactFlowProps` or `Node` for a better developer experience
|
||||||
|
|
||||||
## 12.0.0-next.6
|
## 12.0.0-next.6
|
||||||
|
|
||||||
### Minor changes
|
### Minor changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/react",
|
"name": "@xyflow/react",
|
||||||
"version": "12.0.0-next.6",
|
"version": "12.0.0-next.7",
|
||||||
"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",
|
||||||
|
|||||||
@@ -8,14 +8,27 @@ export enum BackgroundVariant {
|
|||||||
|
|
||||||
export type BackgroundProps = {
|
export type BackgroundProps = {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** Color of the pattern */
|
||||||
color?: string;
|
color?: string;
|
||||||
|
/** Color of the background */
|
||||||
bgColor?: string;
|
bgColor?: string;
|
||||||
|
/** Class applied to the container */
|
||||||
className?: string;
|
className?: string;
|
||||||
|
/** Class applied to the pattern */
|
||||||
patternClassName?: string;
|
patternClassName?: string;
|
||||||
|
/** Gap between repetitions of the pattern */
|
||||||
gap?: number | [number, number];
|
gap?: number | [number, number];
|
||||||
|
/** Size of a single pattern element */
|
||||||
size?: number;
|
size?: number;
|
||||||
|
/** Offset of the pattern */
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
/** Line width of the Line pattern */
|
||||||
lineWidth?: number;
|
lineWidth?: number;
|
||||||
|
/** Variant of the pattern
|
||||||
|
* @example BackgroundVariant.Lines, BackgroundVariant.Dots, BackgroundVariant.Cross
|
||||||
|
* 'lines', 'dots', 'cross'
|
||||||
|
*/
|
||||||
variant?: BackgroundVariant;
|
variant?: BackgroundVariant;
|
||||||
|
/** Style applied to the container */
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,17 +4,31 @@ import type { PanelPosition } from '@xyflow/system';
|
|||||||
import type { FitViewOptions } from '../../types';
|
import type { FitViewOptions } from '../../types';
|
||||||
|
|
||||||
export type ControlProps = {
|
export type ControlProps = {
|
||||||
|
/** Show button for zoom in/out */
|
||||||
showZoom?: boolean;
|
showZoom?: boolean;
|
||||||
|
/** Show button for fit view */
|
||||||
showFitView?: boolean;
|
showFitView?: boolean;
|
||||||
|
/** Show button for toggling interactivity */
|
||||||
showInteractive?: boolean;
|
showInteractive?: boolean;
|
||||||
|
/** Options being used when fit view button is clicked */
|
||||||
fitViewOptions?: FitViewOptions;
|
fitViewOptions?: FitViewOptions;
|
||||||
|
/** Callback when zoom in button is clicked */
|
||||||
onZoomIn?: () => void;
|
onZoomIn?: () => void;
|
||||||
|
/** Callback when zoom out button is clicked */
|
||||||
onZoomOut?: () => void;
|
onZoomOut?: () => void;
|
||||||
|
/** Callback when fit view button is clicked */
|
||||||
onFitView?: () => void;
|
onFitView?: () => void;
|
||||||
|
/** Callback when interactivity is toggled */
|
||||||
onInteractiveChange?: (interactiveStatus: boolean) => void;
|
onInteractiveChange?: (interactiveStatus: boolean) => void;
|
||||||
|
/** Position of the controls on the pane
|
||||||
|
* @example PanelPosition.TopLeft, PanelPosition.TopRight,
|
||||||
|
* PanelPosition.BottomLeft, PanelPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
/** Style applied to container */
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
|
/** ClassName applied to container */
|
||||||
className?: string;
|
className?: string;
|
||||||
'aria-label'?: string;
|
'aria-label'?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,23 +7,44 @@ import type { Node } from '../../types';
|
|||||||
export type GetMiniMapNodeAttribute<NodeType extends Node = Node> = (node: NodeType) => string;
|
export type GetMiniMapNodeAttribute<NodeType extends Node = Node> = (node: NodeType) => string;
|
||||||
|
|
||||||
export type MiniMapProps<NodeType extends Node = Node> = Omit<HTMLAttributes<SVGSVGElement>, 'onClick'> & {
|
export type MiniMapProps<NodeType extends Node = Node> = Omit<HTMLAttributes<SVGSVGElement>, 'onClick'> & {
|
||||||
|
/** Color of nodes on minimap */
|
||||||
nodeColor?: string | GetMiniMapNodeAttribute<NodeType>;
|
nodeColor?: string | GetMiniMapNodeAttribute<NodeType>;
|
||||||
|
/** Stroke color of nodes on minimap */
|
||||||
nodeStrokeColor?: string | GetMiniMapNodeAttribute<NodeType>;
|
nodeStrokeColor?: string | GetMiniMapNodeAttribute<NodeType>;
|
||||||
|
/** ClassName applied to nodes on minimap */
|
||||||
nodeClassName?: string | GetMiniMapNodeAttribute<NodeType>;
|
nodeClassName?: string | GetMiniMapNodeAttribute<NodeType>;
|
||||||
|
/** Border radius of nodes on minimap */
|
||||||
nodeBorderRadius?: number;
|
nodeBorderRadius?: number;
|
||||||
|
/** Stroke width of nodes on minimap */
|
||||||
nodeStrokeWidth?: number;
|
nodeStrokeWidth?: number;
|
||||||
|
/** Component used to render nodes on minimap */
|
||||||
nodeComponent?: ComponentType<MiniMapNodeProps>;
|
nodeComponent?: ComponentType<MiniMapNodeProps>;
|
||||||
|
/** Color of mask representing viewport */
|
||||||
maskColor?: string;
|
maskColor?: string;
|
||||||
|
/** Stroke color of mask representing viewport */
|
||||||
maskStrokeColor?: string;
|
maskStrokeColor?: string;
|
||||||
|
/** Stroke width of mask representing viewport */
|
||||||
maskStrokeWidth?: number;
|
maskStrokeWidth?: number;
|
||||||
|
/** Position of minimap on pane
|
||||||
|
* @example PanelPosition.TopLeft, PanelPosition.TopRight,
|
||||||
|
* PanelPosition.BottomLeft, PanelPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
|
/** Callback caled when minimap is clicked*/
|
||||||
onClick?: (event: MouseEvent, position: XYPosition) => void;
|
onClick?: (event: MouseEvent, position: XYPosition) => void;
|
||||||
|
/** Callback called when node on minimap is clicked */
|
||||||
onNodeClick?: (event: MouseEvent, node: NodeType) => void;
|
onNodeClick?: (event: MouseEvent, node: NodeType) => void;
|
||||||
|
/** If true, viewport is pannable via mini map component */
|
||||||
pannable?: boolean;
|
pannable?: boolean;
|
||||||
|
/** If true, viewport is zoomable via mini map component */
|
||||||
zoomable?: boolean;
|
zoomable?: boolean;
|
||||||
|
/** The aria-label attribute */
|
||||||
ariaLabel?: string | null;
|
ariaLabel?: string | null;
|
||||||
|
/** Invert direction when panning the minimap viewport */
|
||||||
inversePan?: boolean;
|
inversePan?: boolean;
|
||||||
|
/** Step size for zooming in/out on minimap */
|
||||||
zoomStep?: number;
|
zoomStep?: number;
|
||||||
|
/** Offset the viewport on the minmap, acts like a padding */
|
||||||
offsetScale?: number;
|
offsetScale?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,21 +10,39 @@ import type {
|
|||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
export type NodeResizerProps = {
|
export type NodeResizerProps = {
|
||||||
|
/** Id of the node it is resizing
|
||||||
|
* @remarks optional if used inside custom node
|
||||||
|
*/
|
||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
|
/** Color of the resize handle */
|
||||||
color?: string;
|
color?: string;
|
||||||
|
/** ClassName applied to handle */
|
||||||
handleClassName?: string;
|
handleClassName?: string;
|
||||||
|
/** Style applied to handle */
|
||||||
handleStyle?: CSSProperties;
|
handleStyle?: CSSProperties;
|
||||||
|
/** ClassName applied to line */
|
||||||
lineClassName?: string;
|
lineClassName?: string;
|
||||||
|
/** Style applied to line */
|
||||||
lineStyle?: CSSProperties;
|
lineStyle?: CSSProperties;
|
||||||
|
/** Are the controls visible */
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
|
/** Minimum width of node */
|
||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
|
/** Minimum height of node */
|
||||||
minHeight?: number;
|
minHeight?: number;
|
||||||
|
/** Maximum width of node */
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
|
/** Maximum height of node */
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
|
/** Keep aspect ratio when resizing */
|
||||||
keepAspectRatio?: boolean;
|
keepAspectRatio?: boolean;
|
||||||
|
/** Callback to determine if node should resize */
|
||||||
shouldResize?: ShouldResize;
|
shouldResize?: ShouldResize;
|
||||||
|
/** Callback called when resizing starts */
|
||||||
onResizeStart?: OnResizeStart;
|
onResizeStart?: OnResizeStart;
|
||||||
|
/** Callback called when resizing */
|
||||||
onResize?: OnResize;
|
onResize?: OnResize;
|
||||||
|
/** Callback called when resizing ends */
|
||||||
onResizeEnd?: OnResizeEnd;
|
onResizeEnd?: OnResizeEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,7 +60,14 @@ export type ResizeControlProps = Pick<
|
|||||||
| 'onResize'
|
| 'onResize'
|
||||||
| 'onResizeEnd'
|
| 'onResizeEnd'
|
||||||
> & {
|
> & {
|
||||||
|
/** Position of the control
|
||||||
|
* @example ControlPosition.TopLeft, ControlPosition.TopRight,
|
||||||
|
* ControlPosition.BottomLeft, ControlPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: ControlPosition;
|
position?: ControlPosition;
|
||||||
|
/** Variant of the control
|
||||||
|
* @example ResizeControlVariant.Handle, ResizeControlVariant.Line
|
||||||
|
*/
|
||||||
variant?: ResizeControlVariant;
|
variant?: ResizeControlVariant;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
|
|||||||
@@ -2,9 +2,19 @@ import type { HTMLAttributes } from 'react';
|
|||||||
import type { Position, Align } from '@xyflow/system';
|
import type { Position, Align } from '@xyflow/system';
|
||||||
|
|
||||||
export type NodeToolbarProps = HTMLAttributes<HTMLDivElement> & {
|
export type NodeToolbarProps = HTMLAttributes<HTMLDivElement> & {
|
||||||
|
/** Id of the node, or array of ids the toolbar should be displayed at */
|
||||||
nodeId?: string | string[];
|
nodeId?: string | string[];
|
||||||
|
/** If true, node toolbar is visible even if node is not selected */
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
|
/** Position of the toolbar relative to the node
|
||||||
|
* @example Position.TopLeft, Position.TopRight,
|
||||||
|
* Position.BottomLeft, Position.BottomRight
|
||||||
|
*/
|
||||||
position?: Position;
|
position?: Position;
|
||||||
|
/** Offset the toolbar from the node */
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
/** Align the toolbar relative to the node
|
||||||
|
* @example Align.Start, Align.Center, Align.End
|
||||||
|
*/
|
||||||
align?: Align;
|
align?: Align;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export function EdgeUpdateAnchors({
|
|||||||
onConnectEnd,
|
onConnectEnd,
|
||||||
cancelConnection,
|
cancelConnection,
|
||||||
nodes,
|
nodes,
|
||||||
|
rfId: flowId,
|
||||||
panBy,
|
panBy,
|
||||||
updateConnection,
|
updateConnection,
|
||||||
} = store.getState();
|
} = store.getState();
|
||||||
@@ -85,6 +86,7 @@ export function EdgeUpdateAnchors({
|
|||||||
isTarget,
|
isTarget,
|
||||||
edgeUpdaterType: handleType,
|
edgeUpdaterType: handleType,
|
||||||
lib,
|
lib,
|
||||||
|
flowId,
|
||||||
cancelConnection,
|
cancelConnection,
|
||||||
panBy,
|
panBy,
|
||||||
isValidConnection,
|
isValidConnection,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
XYHandle,
|
XYHandle,
|
||||||
getHostForElement,
|
getHostForElement,
|
||||||
isMouseEvent,
|
isMouseEvent,
|
||||||
|
addEdge,
|
||||||
type HandleProps,
|
type HandleProps,
|
||||||
type Connection,
|
type Connection,
|
||||||
type HandleType,
|
type HandleType,
|
||||||
@@ -19,15 +20,14 @@ import {
|
|||||||
|
|
||||||
import { useStore, useStoreApi } from '../../hooks/useStore';
|
import { useStore, useStoreApi } from '../../hooks/useStore';
|
||||||
import { useNodeId } from '../../contexts/NodeIdContext';
|
import { useNodeId } from '../../contexts/NodeIdContext';
|
||||||
import { addEdge } from '../../utils/';
|
|
||||||
import { type ReactFlowState } from '../../types';
|
import { type ReactFlowState } from '../../types';
|
||||||
|
|
||||||
export type HandleComponentProps = HandleProps & Omit<HTMLAttributes<HTMLDivElement>, 'id'>;
|
export type HandleComponentProps = HandleProps & Omit<HTMLAttributes<HTMLDivElement>, 'id'>;
|
||||||
|
|
||||||
const selector = (s: ReactFlowState) => ({
|
const selector = (s: ReactFlowState) => ({
|
||||||
connectionStartHandle: s.connectionStartHandle,
|
|
||||||
connectOnClick: s.connectOnClick,
|
connectOnClick: s.connectOnClick,
|
||||||
noPanClassName: s.noPanClassName,
|
noPanClassName: s.noPanClassName,
|
||||||
|
rfId: s.rfId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const connectingSelector =
|
const connectingSelector =
|
||||||
@@ -70,7 +70,7 @@ const HandleComponent = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
const isTarget = type === 'target';
|
const isTarget = type === 'target';
|
||||||
const store = useStoreApi();
|
const store = useStoreApi();
|
||||||
const nodeId = useNodeId();
|
const nodeId = useNodeId();
|
||||||
const { connectOnClick, noPanClassName } = useStore(selector, shallow);
|
const { connectOnClick, noPanClassName, rfId } = useStore(selector, shallow);
|
||||||
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
||||||
|
|
||||||
if (!nodeId) {
|
if (!nodeId) {
|
||||||
@@ -116,6 +116,7 @@ const HandleComponent = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
isTarget,
|
isTarget,
|
||||||
handleId,
|
handleId,
|
||||||
nodeId,
|
nodeId,
|
||||||
|
flowId: currentStore.rfId,
|
||||||
panBy: currentStore.panBy,
|
panBy: currentStore.panBy,
|
||||||
cancelConnection: currentStore.cancelConnection,
|
cancelConnection: currentStore.cancelConnection,
|
||||||
onConnectStart: currentStore.onConnectStart,
|
onConnectStart: currentStore.onConnectStart,
|
||||||
@@ -142,6 +143,7 @@ const HandleComponent = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
connectionMode,
|
connectionMode,
|
||||||
isValidConnection: isValidConnectionStore,
|
isValidConnection: isValidConnectionStore,
|
||||||
lib,
|
lib,
|
||||||
|
rfId: flowId,
|
||||||
} = store.getState();
|
} = store.getState();
|
||||||
|
|
||||||
if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
|
if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
|
||||||
@@ -167,6 +169,7 @@ const HandleComponent = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
fromHandleId: connectionClickStartHandle.handleId || null,
|
fromHandleId: connectionClickStartHandle.handleId || null,
|
||||||
fromType: connectionClickStartHandle.type,
|
fromType: connectionClickStartHandle.type,
|
||||||
isValidConnection: isValidConnectionHandler,
|
isValidConnection: isValidConnectionHandler,
|
||||||
|
flowId,
|
||||||
doc,
|
doc,
|
||||||
lib,
|
lib,
|
||||||
});
|
});
|
||||||
@@ -185,7 +188,7 @@ const HandleComponent = forwardRef<HTMLDivElement, HandleComponentProps>(
|
|||||||
data-handleid={handleId}
|
data-handleid={handleId}
|
||||||
data-nodeid={nodeId}
|
data-nodeid={nodeId}
|
||||||
data-handlepos={position}
|
data-handlepos={position}
|
||||||
data-id={`${nodeId}-${handleId}-${type}`}
|
data-id={`${rfId}-${nodeId}-${handleId}-${type}`}
|
||||||
className={cc([
|
className={cc([
|
||||||
'react-flow__handle',
|
'react-flow__handle',
|
||||||
`react-flow__handle-${position}`,
|
`react-flow__handle-${position}`,
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import { useStore } from '../../hooks/useStore';
|
|||||||
import type { ReactFlowState } from '../../types';
|
import type { ReactFlowState } from '../../types';
|
||||||
|
|
||||||
export type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
export type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
||||||
|
/** Set position of the panel
|
||||||
|
* @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ import type { Node, NodeChange, Edge, EdgeChange } from '../types';
|
|||||||
*/
|
*/
|
||||||
export function useNodesState<NodeType extends Node = Node>(
|
export function useNodesState<NodeType extends Node = Node>(
|
||||||
initialNodes: NodeType[]
|
initialNodes: NodeType[]
|
||||||
): [NodeType[], Dispatch<SetStateAction<NodeType[]>>, (changes: NodeChange[]) => void] {
|
): [NodeType[], Dispatch<SetStateAction<NodeType[]>>, (changes: NodeChange<NodeType>[]) => void] {
|
||||||
const [nodes, setNodes] = useState(initialNodes);
|
const [nodes, setNodes] = useState(initialNodes);
|
||||||
const onNodesChange = useCallback((changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)), []);
|
const onNodesChange = useCallback(
|
||||||
|
(changes: NodeChange<NodeType>[]) => setNodes((nds) => applyNodeChanges(changes, nds)),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return [nodes, setNodes, onNodesChange];
|
return [nodes, setNodes, onNodesChange];
|
||||||
}
|
}
|
||||||
@@ -28,9 +31,12 @@ export function useNodesState<NodeType extends Node = Node>(
|
|||||||
*/
|
*/
|
||||||
export function useEdgesState<EdgeType extends Edge = Edge>(
|
export function useEdgesState<EdgeType extends Edge = Edge>(
|
||||||
initialEdges: EdgeType[]
|
initialEdges: EdgeType[]
|
||||||
): [EdgeType[], Dispatch<SetStateAction<EdgeType[]>>, (changes: EdgeChange[]) => void] {
|
): [EdgeType[], Dispatch<SetStateAction<EdgeType[]>>, (changes: EdgeChange<EdgeType>[]) => void] {
|
||||||
const [edges, setEdges] = useState(initialEdges);
|
const [edges, setEdges] = useState(initialEdges);
|
||||||
const onEdgesChange = useCallback((changes: EdgeChange[]) => setEdges((eds) => applyEdgeChanges(changes, eds)), []);
|
const onEdgesChange = useCallback(
|
||||||
|
(changes: EdgeChange<EdgeType>[]) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return [edges, setEdges, onEdgesChange];
|
return [edges, setEdges, onEdgesChange];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
|||||||
|
|
||||||
panZoom?.setViewport(viewport, { duration: options?.duration });
|
panZoom?.setViewport(viewport, { duration: options?.duration });
|
||||||
},
|
},
|
||||||
screenToFlowPosition: (position: XYPosition) => {
|
screenToFlowPosition: (position: XYPosition, options: { snapToGrid: boolean } = { snapToGrid: true }) => {
|
||||||
const { transform, snapToGrid, snapGrid, domNode } = store.getState();
|
const { transform, snapGrid, domNode } = store.getState();
|
||||||
|
|
||||||
if (!domNode) {
|
if (!domNode) {
|
||||||
return position;
|
return position;
|
||||||
@@ -100,7 +100,7 @@ const useViewportHelper = (): ViewportHelperFunctions => {
|
|||||||
y: position.y - domY,
|
y: position.y - domY,
|
||||||
};
|
};
|
||||||
|
|
||||||
return pointToRendererPoint(correctedPosition, transform, snapToGrid, snapGrid || [1, 1]);
|
return pointToRendererPoint(correctedPosition, transform, options.snapToGrid, snapGrid);
|
||||||
},
|
},
|
||||||
flowToScreenPosition: (position: XYPosition) => {
|
flowToScreenPosition: (position: XYPosition) => {
|
||||||
const { transform, domNode } = store.getState();
|
const { transform, domNode } = store.getState();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export { useConnection } from './hooks/useConnection';
|
|||||||
export { useNodeId } from './contexts/NodeIdContext';
|
export { useNodeId } from './contexts/NodeIdContext';
|
||||||
|
|
||||||
export { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes';
|
export { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes';
|
||||||
export { isNode, isEdge, getIncomers, getOutgoers, addEdge, updateEdge, getConnectedEdges } from './utils/general';
|
export { isNode, isEdge } from './utils/general';
|
||||||
|
|
||||||
export * from './additional-components';
|
export * from './additional-components';
|
||||||
|
|
||||||
@@ -102,5 +102,10 @@ export {
|
|||||||
getStraightPath,
|
getStraightPath,
|
||||||
getViewportForBounds,
|
getViewportForBounds,
|
||||||
getNodesBounds,
|
getNodesBounds,
|
||||||
|
getIncomers,
|
||||||
|
getOutgoers,
|
||||||
|
addEdge,
|
||||||
|
updateEdge,
|
||||||
|
getConnectedEdges,
|
||||||
internalsSymbol,
|
internalsSymbol,
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ export type NodeReplaceChange<NodeType extends Node = Node> = {
|
|||||||
* Union type of all possible node changes.
|
* Union type of all possible node changes.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export type NodeChange =
|
export type NodeChange<NodeType extends Node = Node> =
|
||||||
| NodeDimensionChange
|
| NodeDimensionChange
|
||||||
| NodePositionChange
|
| NodePositionChange
|
||||||
| NodeSelectionChange
|
| NodeSelectionChange
|
||||||
| NodeRemoveChange
|
| NodeRemoveChange
|
||||||
| NodeAddChange
|
| NodeAddChange<NodeType>
|
||||||
| NodeReplaceChange;
|
| NodeReplaceChange<NodeType>;
|
||||||
|
|
||||||
export type EdgeSelectionChange = NodeSelectionChange;
|
export type EdgeSelectionChange = NodeSelectionChange;
|
||||||
export type EdgeRemoveChange = NodeRemoveChange;
|
export type EdgeRemoveChange = NodeRemoveChange;
|
||||||
@@ -64,4 +64,9 @@ export type EdgeReplaceChange<EdgeType extends Edge = Edge> = {
|
|||||||
item: EdgeType;
|
item: EdgeType;
|
||||||
type: 'replace';
|
type: 'replace';
|
||||||
};
|
};
|
||||||
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange | EdgeReplaceChange;
|
|
||||||
|
export type EdgeChange<EdgeType extends Edge = Edge> =
|
||||||
|
| EdgeSelectionChange
|
||||||
|
| EdgeRemoveChange
|
||||||
|
| EdgeAddChange<EdgeType>
|
||||||
|
| EdgeReplaceChange<EdgeType>;
|
||||||
|
|||||||
@@ -51,118 +51,456 @@ import type {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export type ReactFlowProps = Omit<HTMLAttributes<HTMLDivElement>, 'onError'> & {
|
export type ReactFlowProps = Omit<HTMLAttributes<HTMLDivElement>, 'onError'> & {
|
||||||
|
/** An array of nodes to render in a controlled flow.
|
||||||
|
* @example
|
||||||
|
* const nodes = [
|
||||||
|
* {
|
||||||
|
* id: 'node-1',
|
||||||
|
* type: 'input',
|
||||||
|
* data: { label: 'Node 1' },
|
||||||
|
* position: { x: 250, y: 50 }
|
||||||
|
* }
|
||||||
|
* ];
|
||||||
|
*/
|
||||||
nodes?: Node[];
|
nodes?: Node[];
|
||||||
|
/** An array of edges to render in a controlled flow.
|
||||||
|
* @example
|
||||||
|
* const edges = [
|
||||||
|
* {
|
||||||
|
* id: 'edge-1-2',
|
||||||
|
* source: 'node-1',
|
||||||
|
* target: 'node-2',
|
||||||
|
* }
|
||||||
|
* ];
|
||||||
|
*/
|
||||||
edges?: Edge[];
|
edges?: Edge[];
|
||||||
|
/** The initial nodes to render in an uncontrolled flow. */
|
||||||
defaultNodes?: Node[];
|
defaultNodes?: Node[];
|
||||||
|
/** The initial edges to render in an uncontrolled flow. */
|
||||||
defaultEdges?: Edge[];
|
defaultEdges?: Edge[];
|
||||||
|
/** Defaults to be applied to all new edges that are added to the flow.
|
||||||
|
*
|
||||||
|
* Properties on a new edge will override these defaults if they exist.
|
||||||
|
* @example
|
||||||
|
* const defaultEdgeOptions = {
|
||||||
|
* type: 'customEdgeType',
|
||||||
|
* animated: true,
|
||||||
|
* interactionWidth: 10,
|
||||||
|
* data: { label: 'custom label' },
|
||||||
|
* hidden: false,
|
||||||
|
* deletable: true,
|
||||||
|
* selected: false,
|
||||||
|
* focusable: true,
|
||||||
|
* markerStart: EdgeMarker.ArrowClosed,
|
||||||
|
* markerEnd: EdgeMarker.ArrowClosed,
|
||||||
|
* zIndex: 12,
|
||||||
|
* ariaLabel: 'custom aria label'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||||
|
/** This event handler is called when a user clicks on a node */
|
||||||
onNodeClick?: NodeMouseHandler;
|
onNodeClick?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when a user double clicks on a node */
|
||||||
onNodeDoubleClick?: NodeMouseHandler;
|
onNodeDoubleClick?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user enters a node */
|
||||||
onNodeMouseEnter?: NodeMouseHandler;
|
onNodeMouseEnter?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user moves over a node */
|
||||||
onNodeMouseMove?: NodeMouseHandler;
|
onNodeMouseMove?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user leaves a node */
|
||||||
onNodeMouseLeave?: NodeMouseHandler;
|
onNodeMouseLeave?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when a user right clicks on a node */
|
||||||
onNodeContextMenu?: NodeMouseHandler;
|
onNodeContextMenu?: NodeMouseHandler;
|
||||||
|
/** This event handler is called when a user starts to drag a node */
|
||||||
onNodeDragStart?: NodeDragHandler;
|
onNodeDragStart?: NodeDragHandler;
|
||||||
|
/** This event handler is called when a user drags a node */
|
||||||
onNodeDrag?: NodeDragHandler;
|
onNodeDrag?: NodeDragHandler;
|
||||||
|
/** This event handler is called when a user stops dragging a node */
|
||||||
onNodeDragStop?: NodeDragHandler;
|
onNodeDragStop?: NodeDragHandler;
|
||||||
|
/** This event handler is called when a user clicks on an edge */
|
||||||
onEdgeClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
onEdgeClick?: (event: ReactMouseEvent, edge: Edge) => void;
|
||||||
onEdgeUpdate?: OnEdgeUpdateFunc;
|
/** This event handler is called when a user right clicks on an edge */
|
||||||
onEdgeContextMenu?: EdgeMouseHandler;
|
onEdgeContextMenu?: EdgeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user enters an edge */
|
||||||
onEdgeMouseEnter?: EdgeMouseHandler;
|
onEdgeMouseEnter?: EdgeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user moves over an edge */
|
||||||
onEdgeMouseMove?: EdgeMouseHandler;
|
onEdgeMouseMove?: EdgeMouseHandler;
|
||||||
|
/** This event handler is called when mouse of a user leaves an edge */
|
||||||
onEdgeMouseLeave?: EdgeMouseHandler;
|
onEdgeMouseLeave?: EdgeMouseHandler;
|
||||||
|
/** This event handler is called when a user double clicks on an edge */
|
||||||
onEdgeDoubleClick?: EdgeMouseHandler;
|
onEdgeDoubleClick?: EdgeMouseHandler;
|
||||||
onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge, handleType: HandleType) => void;
|
onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge, handleType: HandleType) => void;
|
||||||
onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void;
|
onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void;
|
||||||
|
onEdgeUpdate?: OnEdgeUpdateFunc;
|
||||||
|
/** This event handler is called when a Node is updated
|
||||||
|
* @example // Use NodesState hook to create edges and get onNodesChange handler
|
||||||
|
* import ReactFlow, { useNodesState } from '@xyflow/react';
|
||||||
|
* const [edges, setNodes, onNodesChange] = useNodesState(initialNodes);
|
||||||
|
*
|
||||||
|
* return (<ReactFlow onNodeChange={onNodeChange} {...rest} />)
|
||||||
|
* @example // Use helper function to update edge
|
||||||
|
* import ReactFlow, { applyNodeChanges } from '@xyflow/react';
|
||||||
|
*
|
||||||
|
* const onNodeChange = useCallback(
|
||||||
|
* (changes) => setNode((eds) => applyNodeChanges(changes, eds)),
|
||||||
|
* [],
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* return (<ReactFlow onNodeChange={onNodeChange} {...rest} />)
|
||||||
|
*/
|
||||||
onNodesChange?: OnNodesChange;
|
onNodesChange?: OnNodesChange;
|
||||||
|
/** This event handler is called when a Edge is updated
|
||||||
|
* @example // Use EdgesState hook to create edges and get onEdgesChange handler
|
||||||
|
* import ReactFlow, { useEdgesState } from '@xyflow/react';
|
||||||
|
* const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
||||||
|
*
|
||||||
|
* return (<ReactFlow onEdgesChange={onEdgesChange} {...rest} />)
|
||||||
|
* @example // Use helper function to update edge
|
||||||
|
* import ReactFlow, { applyEdgeChanges } from '@xyflow/react';
|
||||||
|
*
|
||||||
|
* const onEdgesChange = useCallback(
|
||||||
|
* (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
|
||||||
|
* [],
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* return (<ReactFlow onEdgesChange={onEdgesChange} {...rest} />)
|
||||||
|
*/
|
||||||
onEdgesChange?: OnEdgesChange;
|
onEdgesChange?: OnEdgesChange;
|
||||||
|
/** This event handler gets called when a Node is deleted */
|
||||||
onNodesDelete?: OnNodesDelete;
|
onNodesDelete?: OnNodesDelete;
|
||||||
|
/** This event handler gets called when a Edge is deleted */
|
||||||
onEdgesDelete?: OnEdgesDelete;
|
onEdgesDelete?: OnEdgesDelete;
|
||||||
|
/** This event handler gets called when a Node or Edge is deleted */
|
||||||
onDelete?: OnDelete;
|
onDelete?: OnDelete;
|
||||||
|
/** This event handler gets called when a user starts to drag a selection box */
|
||||||
onSelectionDragStart?: SelectionDragHandler;
|
onSelectionDragStart?: SelectionDragHandler;
|
||||||
|
/** This event handler gets called when a user drags a selection box */
|
||||||
onSelectionDrag?: SelectionDragHandler;
|
onSelectionDrag?: SelectionDragHandler;
|
||||||
|
/** This event handler gets called when a user stops dragging a selection box */
|
||||||
onSelectionDragStop?: SelectionDragHandler;
|
onSelectionDragStop?: SelectionDragHandler;
|
||||||
onSelectionStart?: (event: ReactMouseEvent) => void;
|
onSelectionStart?: (event: ReactMouseEvent) => void;
|
||||||
onSelectionEnd?: (event: ReactMouseEvent) => void;
|
onSelectionEnd?: (event: ReactMouseEvent) => void;
|
||||||
onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void;
|
||||||
|
/** When a connection line is completed and two nodes are connected by the user, this event fires with the new connection.
|
||||||
|
*
|
||||||
|
* You can use the addEdge utility to convert the connection to a complete edge.
|
||||||
|
* @example // Use helper function to update edges onConnect
|
||||||
|
* import ReactFlow, { addEdge } from '@xyflow/react';
|
||||||
|
*
|
||||||
|
* const onConnect = useCallback(
|
||||||
|
* (params) => setEdges((eds) => addEdge(params, eds)),
|
||||||
|
* [],
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* return (<ReactFlow onConnect={onConnect} {...rest} />)
|
||||||
|
*/
|
||||||
onConnect?: OnConnect;
|
onConnect?: OnConnect;
|
||||||
|
/** This event handler gets called when a user starts to drag a connection line */
|
||||||
onConnectStart?: OnConnectStart;
|
onConnectStart?: OnConnectStart;
|
||||||
|
/** This event handler gets called when a user stops dragging a connection line */
|
||||||
onConnectEnd?: OnConnectEnd;
|
onConnectEnd?: OnConnectEnd;
|
||||||
onClickConnectStart?: OnConnectStart;
|
onClickConnectStart?: OnConnectStart;
|
||||||
onClickConnectEnd?: OnConnectEnd;
|
onClickConnectEnd?: OnConnectEnd;
|
||||||
|
/** This event handler gets called when a flow has finished initializing */
|
||||||
onInit?: OnInit;
|
onInit?: OnInit;
|
||||||
|
/** This event handler is called while the user is either panning or zooming the viewport. */
|
||||||
onMove?: OnMove;
|
onMove?: OnMove;
|
||||||
|
/** This event handler gets called when a user starts to pan or zoom the viewport */
|
||||||
onMoveStart?: OnMoveStart;
|
onMoveStart?: OnMoveStart;
|
||||||
|
/** This event handler gets called when a user stops panning or zooming the viewport */
|
||||||
onMoveEnd?: OnMoveEnd;
|
onMoveEnd?: OnMoveEnd;
|
||||||
|
/** This event handler gets called when a user changes group of selected elements in the flow */
|
||||||
onSelectionChange?: OnSelectionChangeFunc;
|
onSelectionChange?: OnSelectionChangeFunc;
|
||||||
|
/** This event handler gets called when user scroll inside the pane */
|
||||||
onPaneScroll?: (event?: WheelEvent) => void;
|
onPaneScroll?: (event?: WheelEvent) => void;
|
||||||
|
/** This event handler gets called when user clicks inside the pane */
|
||||||
onPaneClick?: (event: ReactMouseEvent) => void;
|
onPaneClick?: (event: ReactMouseEvent) => void;
|
||||||
|
/** This event handler gets called when user right clicks inside the pane */
|
||||||
onPaneContextMenu?: (event: ReactMouseEvent | MouseEvent) => void;
|
onPaneContextMenu?: (event: ReactMouseEvent | MouseEvent) => void;
|
||||||
|
/** This event handler gets called when mouse enters the pane */
|
||||||
onPaneMouseEnter?: (event: ReactMouseEvent) => void;
|
onPaneMouseEnter?: (event: ReactMouseEvent) => void;
|
||||||
|
/** This event handler gets called when mouse moves over the pane */
|
||||||
onPaneMouseMove?: (event: ReactMouseEvent) => void;
|
onPaneMouseMove?: (event: ReactMouseEvent) => void;
|
||||||
|
/** This event handler gets called when mouse leaves the pane */
|
||||||
onPaneMouseLeave?: (event: ReactMouseEvent) => void;
|
onPaneMouseLeave?: (event: ReactMouseEvent) => void;
|
||||||
|
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
||||||
onBeforeDelete?: OnBeforeDelete;
|
onBeforeDelete?: OnBeforeDelete;
|
||||||
|
/** Custom node types to be available in a flow.
|
||||||
|
*
|
||||||
|
* React Flow matches a node's type to a component in the nodeTypes object.
|
||||||
|
* @example
|
||||||
|
* import CustomNode from './CustomNode';
|
||||||
|
*
|
||||||
|
* const nodeTypes = { nameOfNodeType: CustomNode };
|
||||||
|
*/
|
||||||
nodeTypes?: NodeTypes;
|
nodeTypes?: NodeTypes;
|
||||||
|
/** Custom edge types to be available in a flow.
|
||||||
|
*
|
||||||
|
* React Flow matches an edge's type to a component in the edgeTypes object.
|
||||||
|
* @example
|
||||||
|
* import CustomEdge from './CustomEdge';
|
||||||
|
*
|
||||||
|
* const edgeTypes = { nameOfEdgeType: CustomEdge };
|
||||||
|
*/
|
||||||
edgeTypes?: EdgeTypes;
|
edgeTypes?: EdgeTypes;
|
||||||
|
/** The type of edge path to use for connection lines.
|
||||||
|
*
|
||||||
|
* Although created edges can be of any type, React Flow needs to know what type of path to render for the connection line before the edge is created!
|
||||||
|
*/
|
||||||
connectionLineType?: ConnectionLineType;
|
connectionLineType?: ConnectionLineType;
|
||||||
|
/** Styles to be applied to the connection line */
|
||||||
connectionLineStyle?: CSSProperties;
|
connectionLineStyle?: CSSProperties;
|
||||||
|
/** React Component to be used as a connection line */
|
||||||
connectionLineComponent?: ConnectionLineComponent;
|
connectionLineComponent?: ConnectionLineComponent;
|
||||||
|
/** Styles to be applied to the container of the connection line */
|
||||||
connectionLineContainerStyle?: CSSProperties;
|
connectionLineContainerStyle?: CSSProperties;
|
||||||
|
/** 'strict' connection mode will only allow you to connect source handles to target handles.
|
||||||
|
*
|
||||||
|
* 'loose' connection mode will allow you to connect handles of any type to one another.
|
||||||
|
* @default 'strict'
|
||||||
|
*/
|
||||||
connectionMode?: ConnectionMode;
|
connectionMode?: ConnectionMode;
|
||||||
|
/** Pressing down this key deletes all selected nodes & edges.
|
||||||
|
* @default 'Backspace'
|
||||||
|
*/
|
||||||
deleteKeyCode?: KeyCode | null;
|
deleteKeyCode?: KeyCode | null;
|
||||||
|
/** If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false.
|
||||||
|
*
|
||||||
|
* By setting this prop to null you can disable this functionality.
|
||||||
|
* @default 'Space'
|
||||||
|
*/
|
||||||
selectionKeyCode?: KeyCode | null;
|
selectionKeyCode?: KeyCode | null;
|
||||||
|
/** Select multiple elements with a selection box, without pressing down selectionKey */
|
||||||
selectionOnDrag?: boolean;
|
selectionOnDrag?: boolean;
|
||||||
|
/** When set to "partial", when the user creates a selection box by click and dragging nodes that are only partially in the box are still selected.
|
||||||
|
* @default 'full'
|
||||||
|
*/
|
||||||
selectionMode?: SelectionMode;
|
selectionMode?: SelectionMode;
|
||||||
|
/** If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false.
|
||||||
|
*
|
||||||
|
* By setting this prop to null you can disable this functionality.
|
||||||
|
* @default 'Space'
|
||||||
|
*/
|
||||||
panActivationKeyCode?: KeyCode | null;
|
panActivationKeyCode?: KeyCode | null;
|
||||||
|
/** Pressing down this key you can select multiple elements by clicking.
|
||||||
|
* @default 'Meta' for macOS, "Ctrl" for other systems
|
||||||
|
*/
|
||||||
multiSelectionKeyCode?: KeyCode | null;
|
multiSelectionKeyCode?: KeyCode | null;
|
||||||
|
/** If a key is set, you can zoom the viewport while that key is held down even if panOnScroll is set to false.
|
||||||
|
*
|
||||||
|
* By setting this prop to null you can disable this functionality.
|
||||||
|
* @default 'Meta' for macOS, "Ctrl" for other systems
|
||||||
|
* */
|
||||||
zoomActivationKeyCode?: KeyCode | null;
|
zoomActivationKeyCode?: KeyCode | null;
|
||||||
|
/** Set this prop to make the flow snap to the grid */
|
||||||
snapToGrid?: boolean;
|
snapToGrid?: boolean;
|
||||||
|
/** Grid all nodes will snap to
|
||||||
|
* @example [20, 20]
|
||||||
|
*/
|
||||||
snapGrid?: SnapGrid;
|
snapGrid?: SnapGrid;
|
||||||
|
/** You can enable this optimisation to instruct Svelte Flow to only render nodes and edges that would be visible in the viewport.
|
||||||
|
*
|
||||||
|
* This might improve performance when you have a large number of nodes and edges but also adds an overhead.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
onlyRenderVisibleElements?: boolean;
|
onlyRenderVisibleElements?: boolean;
|
||||||
|
/** Controls if all nodes should be draggable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
nodesDraggable?: boolean;
|
nodesDraggable?: boolean;
|
||||||
|
/** Controls if all nodes should be connectable to each other
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
nodesConnectable?: boolean;
|
nodesConnectable?: boolean;
|
||||||
|
/** Controls if all nodes should be focusable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
nodesFocusable?: boolean;
|
nodesFocusable?: boolean;
|
||||||
|
/** Defines nodes relative position to its coordinates
|
||||||
|
* @example
|
||||||
|
* [0, 0] // default, top left
|
||||||
|
* [0.5, 0.5] // center
|
||||||
|
* [1, 1] // bottom right
|
||||||
|
*/
|
||||||
nodeOrigin?: NodeOrigin;
|
nodeOrigin?: NodeOrigin;
|
||||||
|
/** Controls if all edges should be focusable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
edgesFocusable?: boolean;
|
edgesFocusable?: boolean;
|
||||||
|
/** Controls if all edges should be updateable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
edgesUpdatable?: boolean;
|
edgesUpdatable?: boolean;
|
||||||
|
/** Controls if all elements should (nodes & edges) be selectable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
elementsSelectable?: boolean;
|
elementsSelectable?: boolean;
|
||||||
|
/** If true, nodes get selected on drag
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
selectNodesOnDrag?: boolean;
|
selectNodesOnDrag?: boolean;
|
||||||
|
/** Enableing this prop allows users to pan the viewport by clicking and dragging.
|
||||||
|
*
|
||||||
|
* You can also set this prop to an array of numbers to limit which mouse buttons can activate panning.
|
||||||
|
* @example [0, 2] // allows panning with the left and right mouse buttons
|
||||||
|
* [0, 1, 2, 3, 4] // allows panning with all mouse buttons
|
||||||
|
*/
|
||||||
panOnDrag?: boolean | number[];
|
panOnDrag?: boolean | number[];
|
||||||
|
/** Minimum zoom level
|
||||||
|
* @default 0.1
|
||||||
|
*/
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
|
/** Maximum zoom level
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
|
/** Controlled viewport to be used instead of internal one */
|
||||||
viewport?: Viewport;
|
viewport?: Viewport;
|
||||||
|
/** Sets the initial position and zoom of the viewport.
|
||||||
|
*
|
||||||
|
* If a default viewport is provided but fitView is enabled, the default viewport will be ignored.
|
||||||
|
* @example
|
||||||
|
* const initialViewport = {
|
||||||
|
* zoom: 0.5,
|
||||||
|
* position: { x: 0, y: 0 }
|
||||||
|
* };
|
||||||
|
*/
|
||||||
defaultViewport?: Viewport;
|
defaultViewport?: Viewport;
|
||||||
|
/**
|
||||||
|
* Gets called when the viewport changes.
|
||||||
|
*/
|
||||||
onViewportChange?: (viewport: Viewport) => void;
|
onViewportChange?: (viewport: Viewport) => void;
|
||||||
|
/** By default the viewport extends infinitely. You can use this prop to set a boundary.
|
||||||
|
*
|
||||||
|
* The first pair of coordinates is the top left boundary and the second pair is the bottom right.
|
||||||
|
* @example [[-1000, -10000], [1000, 1000]]
|
||||||
|
*/
|
||||||
translateExtent?: CoordinateExtent;
|
translateExtent?: CoordinateExtent;
|
||||||
|
/** Disabling this prop will allow the user to scroll the page even when their pointer is over the flow.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
preventScrolling?: boolean;
|
preventScrolling?: boolean;
|
||||||
|
/** By default nodes can be placed on an infinite flow. You can use this prop to set a boundary.
|
||||||
|
*
|
||||||
|
* The first pair of coordinates is the top left boundary and the second pair is the bottom right.
|
||||||
|
* @example [[-1000, -10000], [1000, 1000]]
|
||||||
|
*/
|
||||||
nodeExtent?: CoordinateExtent;
|
nodeExtent?: CoordinateExtent;
|
||||||
|
/** Color of edge markers
|
||||||
|
* @example "#b1b1b7"
|
||||||
|
*/
|
||||||
defaultMarkerColor?: string;
|
defaultMarkerColor?: string;
|
||||||
|
/** Controls if the viewport should zoom by scrolling inside the container */
|
||||||
zoomOnScroll?: boolean;
|
zoomOnScroll?: boolean;
|
||||||
|
/** Controls if the viewport should zoom by pinching on a touch screen */
|
||||||
zoomOnPinch?: boolean;
|
zoomOnPinch?: boolean;
|
||||||
|
/** Controls if the viewport should pan by scrolling inside the container
|
||||||
|
*
|
||||||
|
* Can be limited to a specific direction with panOnScrollMode
|
||||||
|
*/
|
||||||
panOnScroll?: boolean;
|
panOnScroll?: boolean;
|
||||||
|
/** Controls how fast viewport should be panned on scroll.
|
||||||
|
*
|
||||||
|
* Use togther with panOnScroll prop.
|
||||||
|
*/
|
||||||
panOnScrollSpeed?: number;
|
panOnScrollSpeed?: number;
|
||||||
|
/** This prop is used to limit the direction of panning when panOnScroll is enabled.
|
||||||
|
*
|
||||||
|
* The "free" option allows panning in any direction.
|
||||||
|
* @default "free"
|
||||||
|
* @example "horizontal" | "vertical"
|
||||||
|
*/
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
|
/** Controls if the viewport should zoom by double clicking somewhere on the flow */
|
||||||
zoomOnDoubleClick?: boolean;
|
zoomOnDoubleClick?: boolean;
|
||||||
edgeUpdaterRadius?: number;
|
edgeUpdaterRadius?: number;
|
||||||
noDragClassName?: string;
|
noDragClassName?: string;
|
||||||
noWheelClassName?: string;
|
noWheelClassName?: string;
|
||||||
noPanClassName?: string;
|
noPanClassName?: string;
|
||||||
|
/** If set, initial viewport will show all nodes & edges */
|
||||||
fitView?: boolean;
|
fitView?: boolean;
|
||||||
|
/** Options to be used in combination with fitView
|
||||||
|
* @example
|
||||||
|
* const fitViewOptions = {
|
||||||
|
* padding: 0.1,
|
||||||
|
* includeHiddenNodes: false,
|
||||||
|
* minZoom: 0.1,
|
||||||
|
* maxZoom: 1,
|
||||||
|
* duration: 200,
|
||||||
|
* nodes: [{id: 'node-1'}, {id: 'node-2'}], // nodes to fit
|
||||||
|
* };
|
||||||
|
*/
|
||||||
fitViewOptions?: FitViewOptions;
|
fitViewOptions?: FitViewOptions;
|
||||||
|
/**The connectOnClick option lets you click or tap on a source handle to start a connection
|
||||||
|
* and then click on a target handle to complete the connection.
|
||||||
|
*
|
||||||
|
* If you set this option to false, users will need to drag the connection line to the target
|
||||||
|
* handle to create a connection.
|
||||||
|
*/
|
||||||
connectOnClick?: boolean;
|
connectOnClick?: boolean;
|
||||||
|
/** Set position of the attribution
|
||||||
|
* @default 'bottom-right'
|
||||||
|
* @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
|
||||||
|
*/
|
||||||
attributionPosition?: PanelPosition;
|
attributionPosition?: PanelPosition;
|
||||||
|
/** By default, we render a small attribution in the corner of your flows that links back to the project.
|
||||||
|
*
|
||||||
|
* Anyone is free to remove this attribution whether they're a Pro subscriber or not
|
||||||
|
* but we ask that you take a quick look at our {@link https://reactflow.dev/learn/troubleshooting/remove-attribution | removing attribution guide}
|
||||||
|
* before doing so.
|
||||||
|
*/
|
||||||
proOptions?: ProOptions;
|
proOptions?: ProOptions;
|
||||||
|
/** Enabling this option will raise the z-index of nodes when they are selected.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
elevateNodesOnSelect?: boolean;
|
elevateNodesOnSelect?: boolean;
|
||||||
|
/** Enabling this option will raise the z-index of edges when they are selected.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
elevateEdgesOnSelect?: boolean;
|
elevateEdgesOnSelect?: boolean;
|
||||||
|
/**
|
||||||
|
* Can be set true if built-in keyboard controls should be disabled.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
disableKeyboardA11y?: boolean;
|
disableKeyboardA11y?: boolean;
|
||||||
|
/** You can enable this prop to automatically pan the viewport while dragging a node.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
autoPanOnNodeDrag?: boolean;
|
autoPanOnNodeDrag?: boolean;
|
||||||
|
/** You can enable this prop to automatically pan the viewport while dragging a node.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
autoPanOnConnect?: boolean;
|
autoPanOnConnect?: boolean;
|
||||||
|
/** You can enable this prop to automatically pan the viewport while making a new connection.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
connectionRadius?: number;
|
connectionRadius?: number;
|
||||||
|
/** Ocassionally something may happen that causes Svelte Flow to throw an error.
|
||||||
|
*
|
||||||
|
* Instead of exploding your application, we log a message to the console and then call this event handler.
|
||||||
|
* You might use it for additional logging or to show a message to the user.
|
||||||
|
*/
|
||||||
onError?: OnError;
|
onError?: OnError;
|
||||||
|
/** This callback can be used to validate a new connection
|
||||||
|
*
|
||||||
|
* If you return false, the edge will not be added to your flow.
|
||||||
|
* If you have custom connection logic its preferred to use this callback over the isValidConnection prop on the handle component for performance reasons.
|
||||||
|
* @default (connection: Connection) => true
|
||||||
|
*/
|
||||||
isValidConnection?: IsValidConnection;
|
isValidConnection?: IsValidConnection;
|
||||||
|
/** With a threshold greater than zero you can control the distinction between node drag and click events.
|
||||||
|
*
|
||||||
|
* If threshold equals 1, you need to drag the node 1 pixel before a drag event is fired.
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
nodeDragThreshold?: number;
|
nodeDragThreshold?: number;
|
||||||
|
/** Sets a fixed width for the flow */
|
||||||
width?: number;
|
width?: number;
|
||||||
|
/** Sets a fixed height for the flow */
|
||||||
height?: number;
|
height?: number;
|
||||||
|
/** Controls color scheme used for styling the flow
|
||||||
|
* @default 'system'
|
||||||
|
* @example 'system' | 'light' | 'dark'
|
||||||
|
*/
|
||||||
colorMode?: ColorMode;
|
colorMode?: ColorMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -114,13 +114,24 @@ export type EdgeProps<T = any> = Pick<
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export type BaseEdgeProps = EdgeLabelOptions & {
|
export type BaseEdgeProps = EdgeLabelOptions & {
|
||||||
|
/** Unique id of edge */
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** Additional padding where interacting with an edge is still possible */
|
||||||
interactionWidth?: number;
|
interactionWidth?: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
/** The x position of edge label */
|
||||||
labelX?: number;
|
labelX?: number;
|
||||||
|
/** The y position of edge label */
|
||||||
labelY?: number;
|
labelY?: number;
|
||||||
|
/** Marker at start of edge
|
||||||
|
* @example 'url(#arrow)'
|
||||||
|
*/
|
||||||
markerStart?: string;
|
markerStart?: string;
|
||||||
|
/** Marker at end of edge
|
||||||
|
* @example 'url(#arrow)'
|
||||||
|
*/
|
||||||
markerEnd?: string;
|
markerEnd?: string;
|
||||||
|
/** SVG path of the edge */
|
||||||
path: string;
|
path: string;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import {
|
|||||||
import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps } from '.';
|
import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps } from '.';
|
||||||
import { ComponentType } from 'react';
|
import { ComponentType } from 'react';
|
||||||
|
|
||||||
export type OnNodesChange = (changes: NodeChange[]) => void;
|
export type OnNodesChange<NodeType extends Node = Node> = (changes: NodeChange<NodeType>[]) => void;
|
||||||
export type OnEdgesChange = (changes: EdgeChange[]) => void;
|
export type OnEdgesChange<EdgeType extends Edge = Edge> = (changes: EdgeChange<EdgeType>[]) => void;
|
||||||
|
|
||||||
export type OnNodesDelete = (nodes: Node[]) => void;
|
export type OnNodesDelete = (nodes: Node[]) => void;
|
||||||
export type OnEdgesDelete = (edges: Edge[]) => void;
|
export type OnEdgesDelete = (edges: Edge[]) => void;
|
||||||
@@ -55,7 +55,7 @@ export type ViewportHelperFunctions = {
|
|||||||
fitView: FitView;
|
fitView: FitView;
|
||||||
setCenter: SetCenter;
|
setCenter: SetCenter;
|
||||||
fitBounds: FitBounds;
|
fitBounds: FitBounds;
|
||||||
screenToFlowPosition: (position: XYPosition) => XYPosition;
|
screenToFlowPosition: (position: XYPosition, options?: { snapToGrid: boolean }) => XYPosition;
|
||||||
flowToScreenPosition: (position: XYPosition) => XYPosition;
|
flowToScreenPosition: (position: XYPosition) => XYPosition;
|
||||||
viewportInitialized: boolean;
|
viewportInitialized: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ export namespace Instance {
|
|||||||
area: Rect,
|
area: Rect,
|
||||||
partially?: boolean
|
partially?: boolean
|
||||||
) => boolean;
|
) => boolean;
|
||||||
export type getConnectedEdges = (id: string | (Node | { id: Node['id'] })[]) => Edge[];
|
|
||||||
export type getIncomers = (node: string | Node | { id: Node['id'] }) => Node[];
|
|
||||||
export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[];
|
|
||||||
|
|
||||||
export type UpdateNode<NodeType extends Node = Node> = (
|
export type UpdateNode<NodeType extends Node = Node> = (
|
||||||
id: string,
|
id: string,
|
||||||
|
|||||||
@@ -188,7 +188,10 @@ function applyChange(change: any, element: any, elements: any[] = []): any {
|
|||||||
<ReactFLow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
|
<ReactFLow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
export function applyNodeChanges<NodeType extends Node = Node>(changes: NodeChange[], nodes: NodeType[]): NodeType[] {
|
export function applyNodeChanges<NodeType extends Node = Node>(
|
||||||
|
changes: NodeChange<NodeType>[],
|
||||||
|
nodes: NodeType[]
|
||||||
|
): NodeType[] {
|
||||||
return applyChanges(changes, nodes) as NodeType[];
|
return applyChanges(changes, nodes) as NodeType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +215,10 @@ export function applyNodeChanges<NodeType extends Node = Node>(changes: NodeChan
|
|||||||
<ReactFlow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} />
|
<ReactFlow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} />
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
export function applyEdgeChanges<EdgeType extends Edge = Edge>(changes: EdgeChange[], edges: EdgeType[]): EdgeType[] {
|
export function applyEdgeChanges<EdgeType extends Edge = Edge>(
|
||||||
|
changes: EdgeChange<EdgeType>[],
|
||||||
|
edges: EdgeType[]
|
||||||
|
): EdgeType[] {
|
||||||
return applyChanges(changes, edges) as EdgeType[];
|
return applyChanges(changes, edges) as EdgeType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +267,7 @@ export function getElementsDiffChanges({
|
|||||||
lookup,
|
lookup,
|
||||||
}: {
|
}: {
|
||||||
items: Node[] | undefined;
|
items: Node[] | undefined;
|
||||||
lookup: NodeLookup;
|
lookup: NodeLookup<Node>;
|
||||||
}): NodeChange[];
|
}): NodeChange[];
|
||||||
export function getElementsDiffChanges({
|
export function getElementsDiffChanges({
|
||||||
items,
|
items,
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
import {
|
import { isNodeBase, isEdgeBase } from '@xyflow/system';
|
||||||
isNodeBase,
|
|
||||||
isEdgeBase,
|
|
||||||
addEdgeBase,
|
|
||||||
getOutgoersBase,
|
|
||||||
getIncomersBase,
|
|
||||||
updateEdgeBase,
|
|
||||||
getConnectedEdgesBase,
|
|
||||||
} from '@xyflow/system';
|
|
||||||
|
|
||||||
import type { Edge, Node } from '../types';
|
import type { Edge, Node } from '../types';
|
||||||
|
|
||||||
@@ -17,7 +9,8 @@ import type { Edge, Node } from '../types';
|
|||||||
* @param element - The element to test
|
* @param element - The element to test
|
||||||
* @returns A boolean indicating whether the element is an Node
|
* @returns A boolean indicating whether the element is an Node
|
||||||
*/
|
*/
|
||||||
export const isNode = isNodeBase<Node>;
|
export const isNode = <NodeType extends Node = Node>(element: unknown): element is NodeType =>
|
||||||
|
isNodeBase<NodeType>(element);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether an object is useable as an Edge
|
* Test whether an object is useable as an Edge
|
||||||
@@ -26,52 +19,5 @@ export const isNode = isNodeBase<Node>;
|
|||||||
* @param element - The element to test
|
* @param element - The element to test
|
||||||
* @returns A boolean indicating whether the element is an Edge
|
* @returns A boolean indicating whether the element is an Edge
|
||||||
*/
|
*/
|
||||||
export const isEdge = isEdgeBase<Edge>;
|
export const isEdge = <EdgeType extends Edge = Edge>(element: unknown): element is EdgeType =>
|
||||||
|
isEdgeBase<EdgeType>(element);
|
||||||
/**
|
|
||||||
* Pass in a node, and get connected nodes where edge.source === node.id
|
|
||||||
* @public
|
|
||||||
* @param node - The node to get the connected nodes from
|
|
||||||
* @param nodes - The array of all nodes
|
|
||||||
* @param edges - The array of all edges
|
|
||||||
* @returns An array of nodes that are connected over eges where the source is the given node
|
|
||||||
*/
|
|
||||||
export const getOutgoers = getOutgoersBase<Node, Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass in a node, and get connected nodes where edge.target === node.id
|
|
||||||
* @public
|
|
||||||
* @param node - The node to get the connected nodes from
|
|
||||||
* @param nodes - The array of all nodes
|
|
||||||
* @param edges - The array of all edges
|
|
||||||
* @returns An array of nodes that are connected over eges where the target is the given node
|
|
||||||
*/
|
|
||||||
export const getIncomers = getIncomersBase<Node, Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This util is a convenience function to add a new Edge to an array of edges
|
|
||||||
* @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
|
|
||||||
* @public
|
|
||||||
* @param edgeParams - Either an Edge or a Connection you want to add
|
|
||||||
* @param edges - The array of all current edges
|
|
||||||
* @returns A new array of edges with the new edge added
|
|
||||||
*/
|
|
||||||
export const addEdge = addEdgeBase<Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A handy utility to update an existing Edge with new properties
|
|
||||||
* @param oldEdge - The edge you want to update
|
|
||||||
* @param newConnection - The new connection you want to update the edge with
|
|
||||||
* @param edges - The array of all current edges
|
|
||||||
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
|
||||||
* @returns the updated edges array
|
|
||||||
*/
|
|
||||||
export const updateEdge = updateEdgeBase<Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all connecting edges for a given set of nodes
|
|
||||||
* @param nodes - Nodes you want to get the connected edges for
|
|
||||||
* @param edges - All edges
|
|
||||||
* @returns Array of edges that connect any of the given nodes with each other
|
|
||||||
*/
|
|
||||||
export const getConnectedEdges = getConnectedEdgesBase<Node, Edge>;
|
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# @xyflow/svelte
|
# @xyflow/svelte
|
||||||
|
|
||||||
|
## 0.0.34
|
||||||
|
|
||||||
|
## Minor changes
|
||||||
|
|
||||||
|
- add second option param to `screenToFlowPosition` for configuring if `snapToGrid` should be used
|
||||||
|
- add slot to `Controls`
|
||||||
|
- cleanup `ControlButton` types
|
||||||
|
- infer types for `getIncomers`, `getOutgoers`, `updateEdge`, `addEdge` and `getConnectedEdges` thanks @joeyballentine
|
||||||
|
- refactor handles: prefix with flow id for handling nested flows
|
||||||
|
- add comments for types like `SvelteFlowProps` or `Node` for a better developer experience
|
||||||
|
|
||||||
## 0.0.33
|
## 0.0.33
|
||||||
|
|
||||||
### Bugfix
|
### Bugfix
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/svelte",
|
"name": "@xyflow/svelte",
|
||||||
"version": "0.0.33",
|
"version": "0.0.34",
|
||||||
"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",
|
||||||
|
|||||||
@@ -5,10 +5,19 @@ export type BaseEdgeProps = Pick<
|
|||||||
'interactionWidth' | 'label' | 'labelStyle' | 'style'
|
'interactionWidth' | 'label' | 'labelStyle' | 'style'
|
||||||
> & {
|
> & {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** SVG path of the edge */
|
||||||
path: string;
|
path: string;
|
||||||
|
/** The x coordinate of the label */
|
||||||
labelX?: number;
|
labelX?: number;
|
||||||
|
/** The y coordinate of the label */
|
||||||
labelY?: number;
|
labelY?: number;
|
||||||
|
/** Marker at start of edge
|
||||||
|
* @example 'url(#arrow)'
|
||||||
|
*/
|
||||||
markerStart?: string;
|
markerStart?: string;
|
||||||
|
/** Marker at end of edge
|
||||||
|
* @example 'url(#arrow)'
|
||||||
|
*/
|
||||||
markerEnd?: string;
|
markerEnd?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,7 +55,8 @@
|
|||||||
connectionLookup,
|
connectionLookup,
|
||||||
onconnect: onConnectAction,
|
onconnect: onConnectAction,
|
||||||
onconnectstart: onConnectStartAction,
|
onconnectstart: onConnectStartAction,
|
||||||
onconnectend: onConnectEndAction
|
onconnectend: onConnectEndAction,
|
||||||
|
flowId
|
||||||
} = store;
|
} = store;
|
||||||
|
|
||||||
function onPointerDown(event: MouseEvent | TouchEvent) {
|
function onPointerDown(event: MouseEvent | TouchEvent) {
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
connectionMode: $connectionMode,
|
connectionMode: $connectionMode,
|
||||||
lib: $lib,
|
lib: $lib,
|
||||||
autoPanOnConnect: $autoPanOnConnect,
|
autoPanOnConnect: $autoPanOnConnect,
|
||||||
|
flowId: $flowId,
|
||||||
isValidConnection: $isValidConnection,
|
isValidConnection: $isValidConnection,
|
||||||
updateConnection,
|
updateConnection,
|
||||||
cancelConnection,
|
cancelConnection,
|
||||||
@@ -128,7 +130,7 @@
|
|||||||
data-handleid={handleId}
|
data-handleid={handleId}
|
||||||
data-nodeid={nodeId}
|
data-nodeid={nodeId}
|
||||||
data-handlepos={position}
|
data-handlepos={position}
|
||||||
data-id="{nodeId}-{id || null}-{type}"
|
data-id="{flowId}-{nodeId}-{id || null}-{type}"
|
||||||
class={cc([
|
class={cc([
|
||||||
'svelte-flow__handle',
|
'svelte-flow__handle',
|
||||||
`svelte-flow__handle-${position}`,
|
`svelte-flow__handle-${position}`,
|
||||||
|
|||||||
@@ -30,10 +30,14 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { SelectionMode, getEventPosition, getNodesInside } from '@xyflow/system';
|
import {
|
||||||
|
SelectionMode,
|
||||||
|
getEventPosition,
|
||||||
|
getNodesInside,
|
||||||
|
getConnectedEdges
|
||||||
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import { getConnectedEdges } from '$lib/utils';
|
|
||||||
import type { Node, Edge } from '$lib/types';
|
import type { Node, Edge } from '$lib/types';
|
||||||
import type { PaneProps } from './types';
|
import type { PaneProps } from './types';
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import type { HTMLAttributes } from 'svelte/elements';
|
|||||||
export type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
export type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
||||||
'data-testid'?: string;
|
'data-testid'?: string;
|
||||||
'data-message'?: string;
|
'data-message'?: string;
|
||||||
|
/** Set position of the panel
|
||||||
|
* @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
style?: string;
|
style?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
|
|||||||
@@ -36,69 +36,301 @@ import type {
|
|||||||
import type { Writable } from 'svelte/store';
|
import type { Writable } from 'svelte/store';
|
||||||
|
|
||||||
export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
||||||
|
/** The id of the flow
|
||||||
|
*
|
||||||
|
* This is necessary if you want to render multiple flows.
|
||||||
|
* @optional
|
||||||
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** An array of nodes to render in a controlled flow.
|
||||||
|
* @example
|
||||||
|
* const nodes = writable([
|
||||||
|
* {
|
||||||
|
* id: 'node-1',
|
||||||
|
* type: 'input',
|
||||||
|
* data: { label: 'Node 1' },
|
||||||
|
* position: { x: 250, y: 50 }
|
||||||
|
* }
|
||||||
|
* ]);
|
||||||
|
*/
|
||||||
nodes: Writable<Node[]>;
|
nodes: Writable<Node[]>;
|
||||||
|
/** An array of edges to render in a controlled flow.
|
||||||
|
* @example
|
||||||
|
* const edges = writable([
|
||||||
|
* {
|
||||||
|
* id: 'edge-1-2',
|
||||||
|
* source: 'node-1',
|
||||||
|
* target: 'node-2',
|
||||||
|
* }
|
||||||
|
* ]);
|
||||||
|
*/
|
||||||
edges: Writable<Edge[]>;
|
edges: Writable<Edge[]>;
|
||||||
|
/** Custom node types to be available in a flow.
|
||||||
|
*
|
||||||
|
* Svelte Flow matches a node's type to a component in the nodeTypes object.
|
||||||
|
* @example
|
||||||
|
* import CustomNode from './CustomNode.svelte';
|
||||||
|
*
|
||||||
|
* const nodeTypes = { nameOfNodeType: CustomNode };
|
||||||
|
*/
|
||||||
nodeTypes?: NodeTypes;
|
nodeTypes?: NodeTypes;
|
||||||
|
/** Custom edge types to be available in a flow.
|
||||||
|
*
|
||||||
|
* Svelte Flow matches an edge's type to a component in the edgeTypes object.
|
||||||
|
* @example
|
||||||
|
* import CustomEdge from './CustomEdge.svelte';
|
||||||
|
*
|
||||||
|
* const edgeTypes = { nameOfEdgeType: CustomEdge };
|
||||||
|
*/
|
||||||
edgeTypes?: EdgeTypes;
|
edgeTypes?: EdgeTypes;
|
||||||
|
/** Pressing down this key you can select multiple elements with a selection box.
|
||||||
|
* @default 'Shift'
|
||||||
|
*/
|
||||||
selectionKey?: KeyDefinition | null;
|
selectionKey?: KeyDefinition | null;
|
||||||
|
/** If a key is set, you can pan the viewport while that key is held down even if panOnScroll is set to false.
|
||||||
|
*
|
||||||
|
* By setting this prop to null you can disable this functionality.
|
||||||
|
* @default 'Space'
|
||||||
|
*/
|
||||||
panActivationKey?: KeyDefinition | null;
|
panActivationKey?: KeyDefinition | null;
|
||||||
|
/** Pressing down this key deletes all selected nodes & edges.
|
||||||
|
* @default 'Backspace'
|
||||||
|
*/
|
||||||
deleteKey?: KeyDefinition | null;
|
deleteKey?: KeyDefinition | null;
|
||||||
|
/** Pressing down this key you can select multiple elements by clicking.
|
||||||
|
* @default 'Meta' for macOS, "Ctrl" for other systems
|
||||||
|
*/
|
||||||
multiSelectionKey?: KeyDefinition | null;
|
multiSelectionKey?: KeyDefinition | null;
|
||||||
|
/** If a key is set, you can zoom the viewport while that key is held down even if panOnScroll is set to false.
|
||||||
|
*
|
||||||
|
* By setting this prop to null you can disable this functionality.
|
||||||
|
* @default 'Meta' for macOS, "Ctrl" for other systems
|
||||||
|
* */
|
||||||
zoomActivationKey?: KeyDefinition | null;
|
zoomActivationKey?: KeyDefinition | null;
|
||||||
|
/** If set, initial viewport will show all nodes & edges */
|
||||||
fitView?: boolean;
|
fitView?: boolean;
|
||||||
|
/** Options to be used in combination with fitView
|
||||||
|
* @example
|
||||||
|
* const fitViewOptions = {
|
||||||
|
* padding: 0.1,
|
||||||
|
* includeHiddenNodes: false,
|
||||||
|
* minZoom: 0.1,
|
||||||
|
* maxZoom: 1,
|
||||||
|
* duration: 200,
|
||||||
|
* nodes: [{id: 'node-1'}, {id: 'node-2'}], // nodes to fit
|
||||||
|
* };
|
||||||
|
*/
|
||||||
fitViewOptions?: FitViewOptions;
|
fitViewOptions?: FitViewOptions;
|
||||||
|
/** Defines nodes relative position to its coordinates
|
||||||
|
* @example
|
||||||
|
* [0, 0] // default, top left
|
||||||
|
* [0.5, 0.5] // center
|
||||||
|
* [1, 1] // bottom right
|
||||||
|
*/
|
||||||
nodeOrigin?: NodeOrigin;
|
nodeOrigin?: NodeOrigin;
|
||||||
|
/** With a threshold greater than zero you can control the distinction between node drag and click events.
|
||||||
|
*
|
||||||
|
* If threshold equals 1, you need to drag the node 1 pixel before a drag event is fired.
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
nodeDragThreshold?: number;
|
nodeDragThreshold?: number;
|
||||||
|
/** Minimum zoom level
|
||||||
|
* @default 0.1
|
||||||
|
*/
|
||||||
minZoom?: number;
|
minZoom?: number;
|
||||||
|
/** Maximum zoom level
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
maxZoom?: number;
|
maxZoom?: number;
|
||||||
|
/** Sets the initial position and zoom of the viewport.
|
||||||
|
*
|
||||||
|
* If a default viewport is provided but fitView is enabled, the default viewport will be ignored.
|
||||||
|
* @example
|
||||||
|
* const initialViewport = {
|
||||||
|
* zoom: 0.5,
|
||||||
|
* position: { x: 0, y: 0 }
|
||||||
|
* };
|
||||||
|
*/
|
||||||
initialViewport?: Viewport;
|
initialViewport?: Viewport;
|
||||||
|
/** Custom viewport writable to be used instead of internal one */
|
||||||
viewport?: Writable<Viewport>;
|
viewport?: Writable<Viewport>;
|
||||||
|
/** The radius around a handle where you drop a connection line to create a new edge.
|
||||||
|
* @default 20
|
||||||
|
*/
|
||||||
connectionRadius?: number;
|
connectionRadius?: number;
|
||||||
|
/** 'strict' connection mode will only allow you to connect source handles to target handles.
|
||||||
|
*
|
||||||
|
* 'loose' connection mode will allow you to connect handles of any type to one another.
|
||||||
|
* @default 'strict'
|
||||||
|
*/
|
||||||
connectionMode?: ConnectionMode;
|
connectionMode?: ConnectionMode;
|
||||||
|
/** Styles to be applied to the connection line */
|
||||||
connectionLineStyle?: string;
|
connectionLineStyle?: string;
|
||||||
|
/** Styles to be applied to the container of the connection line */
|
||||||
connectionLineContainerStyle?: string;
|
connectionLineContainerStyle?: string;
|
||||||
|
/** When set to "partial", when the user creates a selection box by click and dragging nodes that are only partially in the box are still selected.
|
||||||
|
* @default 'full'
|
||||||
|
*/
|
||||||
selectionMode?: SelectionMode;
|
selectionMode?: SelectionMode;
|
||||||
|
/** Grid all nodes will snap to
|
||||||
|
* @example [20, 20]
|
||||||
|
*/
|
||||||
snapGrid?: SnapGrid;
|
snapGrid?: SnapGrid;
|
||||||
|
/** Color of edge markers
|
||||||
|
* @example "#b1b1b7"
|
||||||
|
*/
|
||||||
defaultMarkerColor?: string;
|
defaultMarkerColor?: string;
|
||||||
|
/** Controls if all nodes should be draggable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
nodesDraggable?: boolean;
|
nodesDraggable?: boolean;
|
||||||
|
/** Controls if all nodes should be connectable to each other
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
nodesConnectable?: boolean;
|
nodesConnectable?: boolean;
|
||||||
|
/** Controls if all elements should (nodes & edges) be selectable
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
elementsSelectable?: boolean;
|
elementsSelectable?: boolean;
|
||||||
|
/** By default the viewport extends infinitely. You can use this prop to set a boundary.
|
||||||
|
*
|
||||||
|
* The first pair of coordinates is the top left boundary and the second pair is the bottom right.
|
||||||
|
* @example [[-1000, -10000], [1000, 1000]]
|
||||||
|
*/
|
||||||
translateExtent?: CoordinateExtent;
|
translateExtent?: CoordinateExtent;
|
||||||
panOnScrollMode?: PanOnScrollMode;
|
/** Disabling this prop will allow the user to scroll the page even when their pointer is over the flow.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
preventScrolling?: boolean;
|
preventScrolling?: boolean;
|
||||||
|
/** Controls if the viewport should zoom by scrolling inside the container */
|
||||||
zoomOnScroll?: boolean;
|
zoomOnScroll?: boolean;
|
||||||
|
/** Controls if the viewport should zoom by double clicking somewhere on the flow */
|
||||||
zoomOnDoubleClick?: boolean;
|
zoomOnDoubleClick?: boolean;
|
||||||
|
/** Controls if the viewport should zoom by pinching on a touch screen */
|
||||||
zoomOnPinch?: boolean;
|
zoomOnPinch?: boolean;
|
||||||
|
/** Controls if the viewport should pan by scrolling inside the container
|
||||||
|
*
|
||||||
|
* Can be limited to a specific direction with panOnScrollMode
|
||||||
|
*/
|
||||||
panOnScroll?: boolean;
|
panOnScroll?: boolean;
|
||||||
|
/** This prop is used to limit the direction of panning when panOnScroll is enabled.
|
||||||
|
*
|
||||||
|
* The "free" option allows panning in any direction.
|
||||||
|
* @default "free"
|
||||||
|
* @example "horizontal" | "vertical"
|
||||||
|
*/
|
||||||
|
panOnScrollMode?: PanOnScrollMode;
|
||||||
|
/** Enableing this prop allows users to pan the viewport by clicking and dragging.
|
||||||
|
*
|
||||||
|
* You can also set this prop to an array of numbers to limit which mouse buttons can activate panning.
|
||||||
|
* @example [0, 2] // allows panning with the left and right mouse buttons
|
||||||
|
* [0, 1, 2, 3, 4] // allows panning with all mouse buttons
|
||||||
|
*/
|
||||||
panOnDrag?: boolean | number[];
|
panOnDrag?: boolean | number[];
|
||||||
|
/** Select multiple elements with a selection box, without pressing down selectionKey */
|
||||||
selectionOnDrag?: boolean;
|
selectionOnDrag?: boolean;
|
||||||
|
/** You can enable this optimisation to instruct Svelte Flow to only render nodes and edges that would be visible in the viewport.
|
||||||
|
*
|
||||||
|
* This might improve performance when you have a large number of nodes and edges but also adds an overhead.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
onlyRenderVisibleElements?: boolean;
|
onlyRenderVisibleElements?: boolean;
|
||||||
|
/** You can enable this prop to automatically pan the viewport while making a new connection.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
autoPanOnConnect?: boolean;
|
autoPanOnConnect?: boolean;
|
||||||
|
/** You can enable this prop to automatically pan the viewport while dragging a node.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
autoPanOnNodeDrag?: boolean;
|
autoPanOnNodeDrag?: boolean;
|
||||||
|
/** Set position of the attribution
|
||||||
|
* @default 'bottom-right'
|
||||||
|
* @example 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
|
||||||
|
*/
|
||||||
attributionPosition?: PanelPosition;
|
attributionPosition?: PanelPosition;
|
||||||
|
/** By default, we render a small attribution in the corner of your flows that links back to the project.
|
||||||
|
*
|
||||||
|
* Anyone is free to remove this attribution whether they're a Pro subscriber or not
|
||||||
|
* but we ask that you take a quick look at our {@link https://reactflow.dev/learn/troubleshooting/remove-attribution | removing attribution guide}
|
||||||
|
* before doing so.
|
||||||
|
*/
|
||||||
proOptions?: ProOptions;
|
proOptions?: ProOptions;
|
||||||
|
/** Defaults to be applied to all new edges that are added to the flow.
|
||||||
|
*
|
||||||
|
* Properties on a new edge will override these defaults if they exist.
|
||||||
|
* @example
|
||||||
|
* const defaultEdgeOptions = {
|
||||||
|
* type: 'customEdgeType',
|
||||||
|
* animated: true,
|
||||||
|
* interactionWidth: 10,
|
||||||
|
* data: { label: 'custom label' },
|
||||||
|
* hidden: false,
|
||||||
|
* deletable: true,
|
||||||
|
* selected: false,
|
||||||
|
* focusable: true,
|
||||||
|
* markerStart: EdgeMarker.ArrowClosed,
|
||||||
|
* markerEnd: EdgeMarker.ArrowClosed,
|
||||||
|
* zIndex: 12,
|
||||||
|
* ariaLabel: 'custom aria label'
|
||||||
|
* }
|
||||||
|
*/
|
||||||
defaultEdgeOptions?: DefaultEdgeOptions;
|
defaultEdgeOptions?: DefaultEdgeOptions;
|
||||||
|
/** Sets a fixed width for the flow */
|
||||||
width?: number;
|
width?: number;
|
||||||
|
/** Sets a fixed height for the flow */
|
||||||
height?: number;
|
height?: number;
|
||||||
|
/** Controls color scheme used for styling the flow
|
||||||
|
* @default 'system'
|
||||||
|
* @example 'system' | 'light' | 'dark'
|
||||||
|
*/
|
||||||
colorMode?: ColorMode;
|
colorMode?: ColorMode;
|
||||||
|
/** Class to be applied to the flow container */
|
||||||
class?: string;
|
class?: string;
|
||||||
|
/** Styles to be applied to the flow container */
|
||||||
style?: string;
|
style?: string;
|
||||||
|
/** Choose from the built-in edge types to be used for connections
|
||||||
|
* @default 'default' | ConnectionLineType.Bezier
|
||||||
|
* @example 'straight' | 'default' | 'step' | 'smoothstep' | 'bezier'
|
||||||
|
* @example ConnectionLineType.Straight | ConnectionLineType.Default | ConnectionLineType.Step | ConnectionLineType.SmoothStep | ConnectionLineType.Bezier
|
||||||
|
*/
|
||||||
connectionLineType?: ConnectionLineType;
|
connectionLineType?: ConnectionLineType;
|
||||||
|
/** This callback can be used to validate a new connection
|
||||||
|
*
|
||||||
|
* If you return false, the edge will not be added to your flow.
|
||||||
|
* If you have custom connection logic its preferred to use this callback over the isValidConnection prop on the handle component for performance reasons.
|
||||||
|
* @default (connection: Connection) => true
|
||||||
|
*/
|
||||||
isValidConnection?: IsValidConnection;
|
isValidConnection?: IsValidConnection;
|
||||||
|
/** This event handler is called when the user begins to pan or zoom the viewport */
|
||||||
onMoveStart?: OnMoveStart;
|
onMoveStart?: OnMoveStart;
|
||||||
|
/** This event handler is called when the user pans or zooms the viewport */
|
||||||
onMove?: OnMove;
|
onMove?: OnMove;
|
||||||
|
/** This event handler is called when the user stops panning or zooming the viewport */
|
||||||
onMoveEnd?: OnMoveEnd;
|
onMoveEnd?: OnMoveEnd;
|
||||||
|
/** Ocassionally something may happen that causes Svelte Flow to throw an error.
|
||||||
|
*
|
||||||
|
* Instead of exploding your application, we log a message to the console and then call this event handler.
|
||||||
|
* You might use it for additional logging or to show a message to the user.
|
||||||
|
*/
|
||||||
onerror?: OnError;
|
onerror?: OnError;
|
||||||
|
/** This handler gets called when the user deletes nodes or edges.
|
||||||
|
* @example
|
||||||
|
* onDelete={({nodes, edges}) => {
|
||||||
|
* console.log('deleted nodes:', nodes);
|
||||||
|
* console.log('deleted edges:', edges);
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
ondelete?: OnDelete;
|
ondelete?: OnDelete;
|
||||||
|
/** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */
|
||||||
onbeforedelete?: OnBeforeDelete;
|
onbeforedelete?: OnBeforeDelete;
|
||||||
|
|
||||||
|
/** This handler gets called when a new edge is created. You can use it to modify the newly created edge. */
|
||||||
onedgecreate?: OnEdgeCreate;
|
onedgecreate?: OnEdgeCreate;
|
||||||
|
|
||||||
|
/** This event gets fired when a connection successfully completes and an edge is created. */
|
||||||
onconnect?: OnConnect;
|
onconnect?: OnConnect;
|
||||||
|
/** When a user starts to drag a connection line, this event gets fired. */
|
||||||
onconnectstart?: OnConnectStart;
|
onconnectstart?: OnConnectStart;
|
||||||
|
/** When a user stops dragging a connection line, this event gets fired. */
|
||||||
onconnectend?: OnConnectEnd;
|
onconnectend?: OnConnectEnd;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function useSvelteFlow(): {
|
|||||||
nodes?: (Node | { id: Node['id'] })[];
|
nodes?: (Node | { id: Node['id'] })[];
|
||||||
edges?: (Edge | { id: Edge['id'] })[];
|
edges?: (Edge | { id: Edge['id'] })[];
|
||||||
}) => Promise<{ deletedNodes: Node[]; deletedEdges: Edge[] }>;
|
}) => Promise<{ deletedNodes: Node[]; deletedEdges: Edge[] }>;
|
||||||
screenToFlowPosition: (position: XYPosition) => XYPosition;
|
screenToFlowPosition: (position: XYPosition, options?: { snapToGrid: boolean }) => XYPosition;
|
||||||
flowToScreenPosition: (position: XYPosition) => XYPosition;
|
flowToScreenPosition: (position: XYPosition) => XYPosition;
|
||||||
viewport: Writable<Viewport>;
|
viewport: Writable<Viewport>;
|
||||||
updateNode: (
|
updateNode: (
|
||||||
@@ -228,14 +228,17 @@ export function useSvelteFlow(): {
|
|||||||
deletedEdges: matchingEdges
|
deletedEdges: matchingEdges
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
screenToFlowPosition: (position: XYPosition) => {
|
screenToFlowPosition: (
|
||||||
|
position: XYPosition,
|
||||||
|
options: { snapToGrid: boolean } = { snapToGrid: true }
|
||||||
|
) => {
|
||||||
const _domNode = get(domNode);
|
const _domNode = get(domNode);
|
||||||
|
|
||||||
if (!_domNode) {
|
if (!_domNode) {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _snapGrid = get(snapGrid);
|
const _snapGrid = options.snapToGrid ? get(snapGrid) : false;
|
||||||
const { x, y, zoom } = get(viewport);
|
const { x, y, zoom } = get(viewport);
|
||||||
const { x: domX, y: domY } = _domNode.getBoundingClientRect();
|
const { x: domX, y: domY } = _domNode.getBoundingClientRect();
|
||||||
const correctedPosition = {
|
const correctedPosition = {
|
||||||
|
|||||||
@@ -112,5 +112,10 @@ export {
|
|||||||
getStraightPath,
|
getStraightPath,
|
||||||
getViewportForBounds,
|
getViewportForBounds,
|
||||||
getNodesBounds,
|
getNodesBounds,
|
||||||
|
getIncomers,
|
||||||
|
getOutgoers,
|
||||||
|
getConnectedEdges,
|
||||||
|
addEdge,
|
||||||
|
updateEdge,
|
||||||
internalsSymbol
|
internalsSymbol
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|||||||
@@ -6,12 +6,23 @@ export enum BackgroundVariant {
|
|||||||
|
|
||||||
export type BackgroundProps = {
|
export type BackgroundProps = {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
/** Color of the background */
|
||||||
bgColor?: string;
|
bgColor?: string;
|
||||||
|
/** Color of the pattern */
|
||||||
patternColor?: string;
|
patternColor?: string;
|
||||||
|
/** Class applied to the pattern */
|
||||||
patternClass?: string;
|
patternClass?: string;
|
||||||
|
/** Class applied to the container */
|
||||||
class?: string;
|
class?: string;
|
||||||
|
/** Gap between repetitions of the pattern */
|
||||||
gap?: number | [number, number];
|
gap?: number | [number, number];
|
||||||
|
/** Size of a single pattern element */
|
||||||
size?: number;
|
size?: number;
|
||||||
|
/** Line width of the Line pattern */
|
||||||
lineWidth?: number;
|
lineWidth?: number;
|
||||||
|
/** Variant of the pattern
|
||||||
|
* @example BackgroundVariant.Lines, BackgroundVariant.Dots, BackgroundVariant.Cross
|
||||||
|
* 'lines', 'dots', 'cross'
|
||||||
|
*/
|
||||||
variant?: BackgroundVariant;
|
variant?: BackgroundVariant;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
|
|
||||||
let className: string;
|
import type { ControlButtonProps } from './types';
|
||||||
let bgColor: string | undefined = undefined;
|
|
||||||
let bgColorHover: string | undefined = undefined;
|
type $$Props = ControlButtonProps;
|
||||||
let color: string | undefined = undefined;
|
|
||||||
let colorHover: string | undefined = undefined;
|
let className: $$Props['class'] = undefined;
|
||||||
let borderColor: string | undefined = undefined;
|
let bgColor: $$Props['bgColor'] = undefined;
|
||||||
|
let bgColorHover: $$Props['bgColorHover'] = undefined;
|
||||||
|
let color: $$Props['color'] = undefined;
|
||||||
|
let colorHover: $$Props['colorHover'] = undefined;
|
||||||
|
let borderColor: $$Props['borderColor'] = undefined;
|
||||||
|
|
||||||
export { className as class };
|
export { className as class };
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
data-testid="svelte-flow__controls"
|
data-testid="svelte-flow__controls"
|
||||||
aria-label={ariaLabel ?? 'Svelte Flow controls'}
|
aria-label={ariaLabel ?? 'Svelte Flow controls'}
|
||||||
>
|
>
|
||||||
|
<slot name="before" />
|
||||||
{#if showZoom}
|
{#if showZoom}
|
||||||
<ControlButton
|
<ControlButton
|
||||||
on:click={onZoomInHandler}
|
on:click={onZoomInHandler}
|
||||||
@@ -118,4 +119,6 @@
|
|||||||
{#if isInteractive}<UnlockIcon />{:else}<LockIcon />{/if}
|
{#if isInteractive}<UnlockIcon />{:else}<LockIcon />{/if}
|
||||||
</ControlButton>
|
</ControlButton>
|
||||||
{/if}
|
{/if}
|
||||||
|
<slot />
|
||||||
|
<slot name="after" />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
||||||
import type { PanelPosition } from '@xyflow/system';
|
import type { PanelPosition } from '@xyflow/system';
|
||||||
|
|
||||||
export type ControlsProps = {
|
export type ControlsProps = {
|
||||||
|
/** Position of the controls on the pane
|
||||||
|
* @example PanelPosition.TopLeft, PanelPosition.TopRight,
|
||||||
|
* PanelPosition.BottomLeft, PanelPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
|
/** Show button for zoom in/out */
|
||||||
showZoom?: boolean;
|
showZoom?: boolean;
|
||||||
|
/** Show button for fit view */
|
||||||
showFitView?: boolean;
|
showFitView?: boolean;
|
||||||
|
/** Show button for toggling interactivity */
|
||||||
showLock?: boolean;
|
showLock?: boolean;
|
||||||
buttonBgColor?: string;
|
buttonBgColor?: string;
|
||||||
buttonBgColorHover?: string;
|
buttonBgColorHover?: string;
|
||||||
@@ -11,3 +19,12 @@ export type ControlsProps = {
|
|||||||
buttonColorHover?: string;
|
buttonColorHover?: string;
|
||||||
'aria-label'?: string;
|
'aria-label'?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ControlButtonProps = HTMLButtonAttributes & {
|
||||||
|
class?: string;
|
||||||
|
bgColor?: string;
|
||||||
|
bgColorHover?: string;
|
||||||
|
color?: string;
|
||||||
|
colorHover?: string;
|
||||||
|
borderColor?: string;
|
||||||
|
};
|
||||||
|
|||||||
@@ -5,25 +5,45 @@ import type { Node } from '$lib/types';
|
|||||||
export type GetMiniMapNodeAttribute = (node: Node) => string;
|
export type GetMiniMapNodeAttribute = (node: Node) => string;
|
||||||
|
|
||||||
export type MiniMapProps = {
|
export type MiniMapProps = {
|
||||||
|
/** Background color of minimap */
|
||||||
bgColor?: string;
|
bgColor?: string;
|
||||||
|
/** Color of nodes on the minimap */
|
||||||
nodeColor?: string | GetMiniMapNodeAttribute;
|
nodeColor?: string | GetMiniMapNodeAttribute;
|
||||||
|
/** Stroke color of nodes on the minimap */
|
||||||
nodeStrokeColor?: string | GetMiniMapNodeAttribute;
|
nodeStrokeColor?: string | GetMiniMapNodeAttribute;
|
||||||
|
/** Class applied to nodes on the minimap */
|
||||||
nodeClass?: string | GetMiniMapNodeAttribute;
|
nodeClass?: string | GetMiniMapNodeAttribute;
|
||||||
|
/** Border radius of nodes on the minimap */
|
||||||
nodeBorderRadius?: number;
|
nodeBorderRadius?: number;
|
||||||
|
/** Stroke width of nodes on the minimap */
|
||||||
nodeStrokeWidth?: number;
|
nodeStrokeWidth?: number;
|
||||||
|
/** Color of the mask representing viewport */
|
||||||
maskColor?: string;
|
maskColor?: string;
|
||||||
|
/** Stroke color of the mask representing viewport */
|
||||||
maskStrokeColor?: string;
|
maskStrokeColor?: string;
|
||||||
|
/** Stroke width of the mask representing viewport */
|
||||||
maskStrokeWidth?: number;
|
maskStrokeWidth?: number;
|
||||||
|
/** Position of the minimap on the pane
|
||||||
|
* @example PanelPosition.TopLeft, PanelPosition.TopRight,
|
||||||
|
* PanelPosition.BottomLeft, PanelPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: PanelPosition;
|
position?: PanelPosition;
|
||||||
|
/** Class applied to container */
|
||||||
class?: string;
|
class?: string;
|
||||||
|
/** Style applied to container */
|
||||||
style?: string;
|
style?: string;
|
||||||
|
/** The aria-label applied to container */
|
||||||
ariaLabel?: string | null;
|
ariaLabel?: string | null;
|
||||||
|
/** Width of minimap */
|
||||||
width?: number;
|
width?: number;
|
||||||
|
/** Height of minimap */
|
||||||
height?: number;
|
height?: number;
|
||||||
// onClick?: (event: MouseEvent, position: XYPosition) => void;
|
// onClick?: (event: MouseEvent, position: XYPosition) => void;
|
||||||
// onNodeClick?: (event: MouseEvent, node: Node) => void;
|
// onNodeClick?: (event: MouseEvent, node: Node) => void;
|
||||||
pannable?: boolean;
|
pannable?: boolean;
|
||||||
zoomable?: boolean;
|
zoomable?: boolean;
|
||||||
|
/** Invert the direction when panning the minimap viewport */
|
||||||
inversePan?: boolean;
|
inversePan?: boolean;
|
||||||
|
/** Step size for zooming in/out */
|
||||||
zoomStep?: number;
|
zoomStep?: number;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,21 +8,39 @@ import type {
|
|||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
export type NodeResizerProps = {
|
export type NodeResizerProps = {
|
||||||
|
/** Id of the node it is resizing
|
||||||
|
* @remarks optional if used inside custom node
|
||||||
|
*/
|
||||||
nodeId?: string;
|
nodeId?: string;
|
||||||
|
/** Color of the resize handle */
|
||||||
color?: string;
|
color?: string;
|
||||||
|
/** Class applied to handle */
|
||||||
handleClass?: string;
|
handleClass?: string;
|
||||||
|
/** Style applied to handle */
|
||||||
handleStyle?: string;
|
handleStyle?: string;
|
||||||
|
/** Class applied to line */
|
||||||
lineClass?: string;
|
lineClass?: string;
|
||||||
|
/** Style applied to line */
|
||||||
lineStyle?: string;
|
lineStyle?: string;
|
||||||
|
/** Are the controls visible */
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
|
/** Minimum width of node */
|
||||||
minWidth?: number;
|
minWidth?: number;
|
||||||
|
/** Minimum height of node */
|
||||||
minHeight?: number;
|
minHeight?: number;
|
||||||
|
/** Maximum width of node */
|
||||||
maxWidth?: number;
|
maxWidth?: number;
|
||||||
|
/** Maximum height of node */
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
|
/** Keep aspect ratio when resizing */
|
||||||
keepAspectRatio?: boolean;
|
keepAspectRatio?: boolean;
|
||||||
|
/** Callback to determine if node should resize */
|
||||||
shouldResize?: ShouldResize;
|
shouldResize?: ShouldResize;
|
||||||
|
/** Callback called when resizing starts */
|
||||||
onResizeStart?: OnResizeStart;
|
onResizeStart?: OnResizeStart;
|
||||||
|
/** Callback called when resizing */
|
||||||
onResize?: OnResize;
|
onResize?: OnResize;
|
||||||
|
/** Callback called when resizing ends */
|
||||||
onResizeEnd?: OnResizeEnd;
|
onResizeEnd?: OnResizeEnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,7 +58,14 @@ export type ResizeControlProps = Pick<
|
|||||||
| 'onResize'
|
| 'onResize'
|
||||||
| 'onResizeEnd'
|
| 'onResizeEnd'
|
||||||
> & {
|
> & {
|
||||||
|
/** Position of control
|
||||||
|
* @example ControlPosition.TopLeft, ControlPosition.TopRight,
|
||||||
|
* ControlPosition.BottomLeft, ControlPosition.BottomRight
|
||||||
|
*/
|
||||||
position?: ControlPosition;
|
position?: ControlPosition;
|
||||||
|
/** Variant of control
|
||||||
|
* @example ResizeControlVariant.Handle, ResizeControlVariant.Line
|
||||||
|
*/
|
||||||
variant?: ResizeControlVariant;
|
variant?: ResizeControlVariant;
|
||||||
class?: string;
|
class?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
import type { Position, Align } from '@xyflow/system';
|
import type { Position, Align } from '@xyflow/system';
|
||||||
|
|
||||||
export type NodeToolbarProps = {
|
export type NodeToolbarProps = {
|
||||||
|
/** The id of the node, or array of ids the toolbar should be displayed at */
|
||||||
nodeId?: string | string[];
|
nodeId?: string | string[];
|
||||||
|
/** Position of the toolbar relative to the node
|
||||||
|
* @example Position.TopLeft, Position.TopRight,
|
||||||
|
* Position.BottomLeft, Position.BottomRight
|
||||||
|
*/
|
||||||
position?: Position;
|
position?: Position;
|
||||||
|
/** Align the toolbar relative to the node
|
||||||
|
* @example Align.Start, Align.Center, Align.End
|
||||||
|
*/
|
||||||
align?: Align;
|
align?: Align;
|
||||||
|
/** Offset the toolbar from the node */
|
||||||
offset?: number;
|
offset?: number;
|
||||||
|
/** If true, node toolbar is visible even if node is not selected */
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
getElementsToRemove,
|
getElementsToRemove,
|
||||||
panBy as panBySystem,
|
panBy as panBySystem,
|
||||||
updateNodeDimensions as updateNodeDimensionsSystem,
|
updateNodeDimensions as updateNodeDimensionsSystem,
|
||||||
|
addEdge as addEdgeUtil,
|
||||||
type UpdateNodePositions,
|
type UpdateNodePositions,
|
||||||
type NodeDimensionUpdate,
|
type NodeDimensionUpdate,
|
||||||
type ViewportHelperFunctionOptions,
|
type ViewportHelperFunctionOptions,
|
||||||
@@ -19,7 +20,6 @@ import {
|
|||||||
errorMessages
|
errorMessages
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { addEdge as addEdgeUtil } from '$lib/utils';
|
|
||||||
import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions, ConnectionData } from '$lib/types';
|
import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions, ConnectionData } from '$lib/types';
|
||||||
import { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store';
|
import { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store';
|
||||||
import type { SvelteFlowStore } from './types';
|
import type { SvelteFlowStore } from './types';
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export const getInitialStore = ({
|
|||||||
return {
|
return {
|
||||||
flowId: writable<string | null>(null),
|
flowId: writable<string | null>(null),
|
||||||
nodes: createNodesStore(nextNodes, nodeLookup),
|
nodes: createNodesStore(nextNodes, nodeLookup),
|
||||||
nodeLookup: readable<NodeLookup>(nodeLookup),
|
nodeLookup: readable<NodeLookup<Node>>(nodeLookup),
|
||||||
edgeLookup: readable<EdgeLookup>(edgeLookup),
|
edgeLookup: readable<EdgeLookup>(edgeLookup),
|
||||||
visibleNodes: readable<Node[]>([]),
|
visibleNodes: readable<Node[]>([]),
|
||||||
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
||||||
|
|||||||
@@ -23,13 +23,26 @@ export type ConnectionData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type HandleComponentProps = {
|
export type HandleComponentProps = {
|
||||||
|
/** Type of the handle
|
||||||
|
* @example HandleType.Source, HandleType.Target
|
||||||
|
*/
|
||||||
type: HandleType;
|
type: HandleType;
|
||||||
|
/** Position of the handle
|
||||||
|
* @example Position.TopLeft, Position.TopRight,
|
||||||
|
* Position.BottomLeft, Position.BottomRight
|
||||||
|
*/
|
||||||
position?: Position;
|
position?: Position;
|
||||||
|
/** Id of the handle
|
||||||
|
* @remarks optional if there is only one handle of this type
|
||||||
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
style?: string;
|
style?: string;
|
||||||
|
/** Should you be able to connect from/to this handle */
|
||||||
isConnectable?: boolean;
|
isConnectable?: boolean;
|
||||||
|
/** Shoould you be able to connect from this handle */
|
||||||
isConnectableStart?: boolean;
|
isConnectableStart?: boolean;
|
||||||
|
/** Should you be able to connect to this handle */
|
||||||
isConnectableEnd?: boolean;
|
isConnectableEnd?: boolean;
|
||||||
onconnect?: (connections: Connection[]) => void;
|
onconnect?: (connections: Connection[]) => void;
|
||||||
ondisconnect?: (connections: Connection[]) => void;
|
ondisconnect?: (connections: Connection[]) => void;
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
import {
|
import { isNodeBase, isEdgeBase } from '@xyflow/system';
|
||||||
isNodeBase,
|
|
||||||
isEdgeBase,
|
|
||||||
addEdgeBase,
|
|
||||||
getOutgoersBase,
|
|
||||||
getIncomersBase,
|
|
||||||
updateEdgeBase,
|
|
||||||
getConnectedEdgesBase
|
|
||||||
} from '@xyflow/system';
|
|
||||||
|
|
||||||
import type { Edge, Node } from '$lib/types';
|
import type { Edge, Node } from '$lib/types';
|
||||||
|
|
||||||
@@ -17,7 +9,8 @@ import type { Edge, Node } from '$lib/types';
|
|||||||
* @param element - The element to test
|
* @param element - The element to test
|
||||||
* @returns A boolean indicating whether the element is an Node
|
* @returns A boolean indicating whether the element is an Node
|
||||||
*/
|
*/
|
||||||
export const isNode = isNodeBase<Node>;
|
export const isNode = <NodeType extends Node = Node>(element: unknown): element is NodeType =>
|
||||||
|
isNodeBase<NodeType>(element);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether an object is useable as an Edge
|
* Test whether an object is useable as an Edge
|
||||||
@@ -26,52 +19,5 @@ export const isNode = isNodeBase<Node>;
|
|||||||
* @param element - The element to test
|
* @param element - The element to test
|
||||||
* @returns A boolean indicating whether the element is an Edge
|
* @returns A boolean indicating whether the element is an Edge
|
||||||
*/
|
*/
|
||||||
export const isEdge = isEdgeBase<Edge>;
|
export const isEdge = <EdgeType extends Edge = Edge>(element: unknown): element is EdgeType =>
|
||||||
|
isEdgeBase<EdgeType>(element);
|
||||||
/**
|
|
||||||
* Pass in a node, and get connected nodes where edge.source === node.id
|
|
||||||
* @public
|
|
||||||
* @param node - The node to get the connected nodes from
|
|
||||||
* @param nodes - The array of all nodes
|
|
||||||
* @param edges - The array of all edges
|
|
||||||
* @returns An array of nodes that are connected over eges where the source is the given node
|
|
||||||
*/
|
|
||||||
export const getOutgoers = getOutgoersBase<Node, Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass in a node, and get connected nodes where edge.target === node.id
|
|
||||||
* @public
|
|
||||||
* @param node - The node to get the connected nodes from
|
|
||||||
* @param nodes - The array of all nodes
|
|
||||||
* @param edges - The array of all edges
|
|
||||||
* @returns An array of nodes that are connected over eges where the target is the given node
|
|
||||||
*/
|
|
||||||
export const getIncomers = getIncomersBase<Node, Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This util is a convenience function to add a new Edge to an array of edges
|
|
||||||
* @remarks It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
|
|
||||||
* @public
|
|
||||||
* @param edgeParams - Either an Edge or a Connection you want to add
|
|
||||||
* @param edges - The array of all current edges
|
|
||||||
* @returns A new array of edges with the new edge added
|
|
||||||
*/
|
|
||||||
export const addEdge = addEdgeBase<Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A handy utility to update an existing Edge with new properties
|
|
||||||
* @param oldEdge - The edge you want to update
|
|
||||||
* @param newConnection - The new connection you want to update the edge with
|
|
||||||
* @param edges - The array of all current edges
|
|
||||||
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
|
||||||
* @returns the updated edges array
|
|
||||||
*/
|
|
||||||
export const updateEdge = updateEdgeBase<Edge>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all connecting edges for a given set of nodes
|
|
||||||
* @param nodes - Nodes you want to get the connected edges for
|
|
||||||
* @param edges - All edges
|
|
||||||
* @returns Array of edges that connect any of the given nodes with each other
|
|
||||||
*/
|
|
||||||
export const getConnectedEdges = getConnectedEdgesBase<Node, Edge>;
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@xyflow/system",
|
"name": "@xyflow/system",
|
||||||
"version": "0.0.14",
|
"version": "0.0.15",
|
||||||
"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",
|
||||||
|
|||||||
@@ -2,22 +2,40 @@ import { Position } from './utils';
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type EdgeBase<EdgeData = any> = {
|
export type EdgeBase<EdgeData = any> = {
|
||||||
|
/** Unique id of an edge */
|
||||||
id: string;
|
id: string;
|
||||||
|
/** Type of an edge defined in edgeTypes */
|
||||||
type?: string;
|
type?: string;
|
||||||
|
/** Id of source node */
|
||||||
source: string;
|
source: string;
|
||||||
|
/** Id of target node */
|
||||||
target: string;
|
target: string;
|
||||||
|
/** Id of source handle
|
||||||
|
* only needed if there are multiple handles per node
|
||||||
|
*/
|
||||||
sourceHandle?: string | null;
|
sourceHandle?: string | null;
|
||||||
|
/** Id of target handle
|
||||||
|
* only needed if there are multiple handles per node
|
||||||
|
*/
|
||||||
targetHandle?: string | null;
|
targetHandle?: string | null;
|
||||||
animated?: boolean;
|
animated?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
deletable?: boolean;
|
deletable?: boolean;
|
||||||
selectable?: boolean;
|
selectable?: boolean;
|
||||||
|
/** Arbitrary data passed to an edge */
|
||||||
data?: EdgeData;
|
data?: EdgeData;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
|
/** Set the marker on the beginning of an edge
|
||||||
|
* @example 'arrow', 'arrowclosed' or custom marker
|
||||||
|
*/
|
||||||
markerStart?: EdgeMarkerType;
|
markerStart?: EdgeMarkerType;
|
||||||
|
/** Set the marker on the end of an edge
|
||||||
|
* @example 'arrow', 'arrowclosed' or custom marker
|
||||||
|
*/
|
||||||
markerEnd?: EdgeMarkerType;
|
markerEnd?: EdgeMarkerType;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
|
/** Padding around the edge where interaction is still possible */
|
||||||
interactionWidth?: number;
|
interactionWidth?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,29 @@ export type ConnectionHandle = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type HandleProps = {
|
export type HandleProps = {
|
||||||
|
/** Type of the handle
|
||||||
|
* @example HandleType.Source, HandleType.Target
|
||||||
|
*/
|
||||||
type: HandleType;
|
type: HandleType;
|
||||||
|
/** Position of the handle
|
||||||
|
* @example Position.TopLeft, Position.TopRight,
|
||||||
|
* Position.BottomLeft, Position.BottomRight
|
||||||
|
*/
|
||||||
position: Position;
|
position: Position;
|
||||||
|
/** Should you be able to connect to/from this handle */
|
||||||
isConnectable?: boolean;
|
isConnectable?: boolean;
|
||||||
|
/** Should you be able to connect from this handle */
|
||||||
isConnectableStart?: boolean;
|
isConnectableStart?: boolean;
|
||||||
|
/** Should you be able to connect to this handle */
|
||||||
isConnectableEnd?: boolean;
|
isConnectableEnd?: boolean;
|
||||||
|
/** Callback called when connection is made */
|
||||||
onConnect?: OnConnect;
|
onConnect?: OnConnect;
|
||||||
|
/** Callback if connection is valid
|
||||||
|
* @remarks connection becomes an edge if isValidConnection returns true
|
||||||
|
*/
|
||||||
isValidConnection?: IsValidConnection;
|
isValidConnection?: IsValidConnection;
|
||||||
|
/** Id of the handle
|
||||||
|
* @remarks optional if there is only one handle of this type
|
||||||
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,16 +3,34 @@ import { internalsSymbol } from '../constants';
|
|||||||
import type { XYPosition, Position, CoordinateExtent, HandleElement } from '.';
|
import type { XYPosition, Position, CoordinateExtent, HandleElement } from '.';
|
||||||
import { Optional } from '../utils/types';
|
import { Optional } from '../utils/types';
|
||||||
|
|
||||||
// this is stuff that all nodes share independent of the framework
|
/**
|
||||||
|
* Framework independent node data structure.
|
||||||
|
*
|
||||||
|
* @typeParam T - type of the node data
|
||||||
|
* @typeParam U - type of the node
|
||||||
|
*/
|
||||||
export type NodeBase<T = any, U extends string | undefined = string | undefined> = {
|
export type NodeBase<T = any, U extends string | undefined = string | undefined> = {
|
||||||
|
/** Unique id of a node */
|
||||||
id: string;
|
id: string;
|
||||||
|
/** Position of a node on the pane
|
||||||
|
* @example { x: 0, y: 0 }
|
||||||
|
*/
|
||||||
position: XYPosition;
|
position: XYPosition;
|
||||||
|
/** Arbitrary data passed to a node */
|
||||||
data: T;
|
data: T;
|
||||||
|
/** Type of node defined in nodeTypes */
|
||||||
type?: U;
|
type?: U;
|
||||||
|
/** Only relevant for default, source, target nodeType. controls source position
|
||||||
|
* @example 'right', 'left', 'top', 'bottom'
|
||||||
|
*/
|
||||||
sourcePosition?: Position;
|
sourcePosition?: Position;
|
||||||
|
/** Only relevant for default, source, target nodeType. controls target position
|
||||||
|
* @example 'right', 'left', 'top', 'bottom'
|
||||||
|
*/
|
||||||
targetPosition?: Position;
|
targetPosition?: Position;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
|
/** True, if node is being dragged */
|
||||||
dragging?: boolean;
|
dragging?: boolean;
|
||||||
draggable?: boolean;
|
draggable?: boolean;
|
||||||
selectable?: boolean;
|
selectable?: boolean;
|
||||||
@@ -21,11 +39,21 @@ export type NodeBase<T = any, U extends string | undefined = string | undefined>
|
|||||||
dragHandle?: string;
|
dragHandle?: string;
|
||||||
width?: number | null;
|
width?: number | null;
|
||||||
height?: number | null;
|
height?: number | null;
|
||||||
|
/** Parent node id, used for creating sub-flows */
|
||||||
parentNode?: string;
|
parentNode?: string;
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
|
/** Boundary a node can be moved in
|
||||||
|
* @example 'parent' or [[0, 0], [100, 100]]
|
||||||
|
*/
|
||||||
extent?: 'parent' | CoordinateExtent;
|
extent?: 'parent' | CoordinateExtent;
|
||||||
expandParent?: boolean;
|
expandParent?: boolean;
|
||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
|
/** Origin of the node relative to it's position
|
||||||
|
* @example
|
||||||
|
* [0.5, 0.5] // centers the node
|
||||||
|
* [0, 0] // top left
|
||||||
|
* [1, 1] // bottom right
|
||||||
|
*/
|
||||||
origin?: NodeOrigin;
|
origin?: NodeOrigin;
|
||||||
handles?: NodeHandle[];
|
handles?: NodeHandle[];
|
||||||
computed?: {
|
computed?: {
|
||||||
@@ -34,7 +62,7 @@ export type NodeBase<T = any, U extends string | undefined = string | undefined>
|
|||||||
positionAbsolute?: XYPosition;
|
positionAbsolute?: XYPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
// only used internally
|
// Only used internally
|
||||||
[internalsSymbol]?: {
|
[internalsSymbol]?: {
|
||||||
z?: number;
|
z?: number;
|
||||||
handleBounds?: NodeHandleBounds;
|
handleBounds?: NodeHandleBounds;
|
||||||
@@ -47,7 +75,14 @@ export type NodeBase<T = any, U extends string | undefined = string | undefined>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// props that get passed to a custom node
|
// props that get passed to a custom node
|
||||||
|
/**
|
||||||
|
* The node data structure that gets used for the nodes prop.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param id - The id of the node.
|
||||||
|
*/
|
||||||
export type NodeProps<T = any> = {
|
export type NodeProps<T = any> = {
|
||||||
|
/** Id of the node */
|
||||||
id: NodeBase['id'];
|
id: NodeBase['id'];
|
||||||
data: T;
|
data: T;
|
||||||
dragHandle: NodeBase['dragHandle'];
|
dragHandle: NodeBase['dragHandle'];
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => {
|
|||||||
* @param edges - The array of all current edges
|
* @param edges - The array of all current edges
|
||||||
* @returns A new array of edges with the new edge added
|
* @returns A new array of edges with the new edge added
|
||||||
*/
|
*/
|
||||||
export const addEdgeBase = <EdgeType extends EdgeBase>(
|
export const addEdge = <EdgeType extends EdgeBase>(
|
||||||
edgeParams: EdgeType | Connection,
|
edgeParams: EdgeType | Connection,
|
||||||
edges: EdgeType[]
|
edges: EdgeType[]
|
||||||
): EdgeType[] => {
|
): EdgeType[] => {
|
||||||
@@ -145,7 +145,7 @@ export type UpdateEdgeOptions = {
|
|||||||
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
* @param options.shouldReplaceId - should the id of the old edge be replaced with the new connection id
|
||||||
* @returns the updated edges array
|
* @returns the updated edges array
|
||||||
*/
|
*/
|
||||||
export const updateEdgeBase = <EdgeType extends EdgeBase>(
|
export const updateEdge = <EdgeType extends EdgeBase>(
|
||||||
oldEdge: EdgeType,
|
oldEdge: EdgeType,
|
||||||
newConnection: Connection,
|
newConnection: Connection,
|
||||||
edges: EdgeType[],
|
edges: EdgeType[],
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const isNodeBase = <NodeType extends NodeBase = NodeBase>(element: any):
|
|||||||
* @param edges - The array of all edges
|
* @param edges - The array of all edges
|
||||||
* @returns An array of nodes that are connected over eges where the source is the given node
|
* @returns An array of nodes that are connected over eges where the source is the given node
|
||||||
*/
|
*/
|
||||||
export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
export const getOutgoers = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||||
node: NodeType | { id: string },
|
node: NodeType | { id: string },
|
||||||
nodes: NodeType[],
|
nodes: NodeType[],
|
||||||
edges: EdgeType[]
|
edges: EdgeType[]
|
||||||
@@ -81,7 +81,7 @@ export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType e
|
|||||||
* @param edges - The array of all edges
|
* @param edges - The array of all edges
|
||||||
* @returns An array of nodes that are connected over eges where the target is the given node
|
* @returns An array of nodes that are connected over eges where the target is the given node
|
||||||
*/
|
*/
|
||||||
export const getIncomersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
export const getIncomers = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||||
node: NodeType | { id: string },
|
node: NodeType | { id: string },
|
||||||
nodes: NodeType[],
|
nodes: NodeType[],
|
||||||
edges: EdgeType[]
|
edges: EdgeType[]
|
||||||
@@ -148,7 +148,7 @@ export const getNodesBounds = (nodes: NodeBase[], nodeOrigin: NodeOrigin = [0, 0
|
|||||||
|
|
||||||
const box = nodes.reduce(
|
const box = nodes.reduce(
|
||||||
(currBox, node) => {
|
(currBox, node) => {
|
||||||
const { x, y } = getNodePositionWithOrigin(node, node.origin || nodeOrigin).positionAbsolute;
|
const { x, y } = getNodePositionWithOrigin(node, node.origin || nodeOrigin);
|
||||||
return getBoundsOfBoxes(
|
return getBoundsOfBoxes(
|
||||||
currBox,
|
currBox,
|
||||||
rectToBox({
|
rectToBox({
|
||||||
@@ -212,7 +212,7 @@ export const getNodesInside = <NodeType extends NodeBase>(
|
|||||||
* @param edges - All edges
|
* @param edges - All edges
|
||||||
* @returns Array of edges that connect any of the given nodes with each other
|
* @returns Array of edges that connect any of the given nodes with each other
|
||||||
*/
|
*/
|
||||||
export const getConnectedEdgesBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
export const getConnectedEdges = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
|
||||||
nodes: NodeType[],
|
nodes: NodeType[],
|
||||||
edges: EdgeType[]
|
edges: EdgeType[]
|
||||||
): EdgeType[] => {
|
): EdgeType[] => {
|
||||||
@@ -370,7 +370,7 @@ export async function getElementsToRemove<NodeType extends NodeBase = NodeBase,
|
|||||||
|
|
||||||
const edgeIds = edgesToRemove.map((edge) => edge.id);
|
const edgeIds = edgesToRemove.map((edge) => edge.id);
|
||||||
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
|
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
|
||||||
const connectedEdges = getConnectedEdgesBase(matchingNodes, deletableEdges);
|
const connectedEdges = getConnectedEdges(matchingNodes, deletableEdges);
|
||||||
const matchingEdges: EdgeType[] = connectedEdges;
|
const matchingEdges: EdgeType[] = connectedEdges;
|
||||||
|
|
||||||
for (const edge of deletableEdges) {
|
for (const edge of deletableEdges) {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export type OnPointerDownParams = {
|
|||||||
isTarget: boolean;
|
isTarget: boolean;
|
||||||
nodes: NodeBase[];
|
nodes: NodeBase[];
|
||||||
lib: string;
|
lib: string;
|
||||||
|
flowId: string | null;
|
||||||
edgeUpdaterType?: HandleType;
|
edgeUpdaterType?: HandleType;
|
||||||
updateConnection: UpdateConnection;
|
updateConnection: UpdateConnection;
|
||||||
panBy: PanBy;
|
panBy: PanBy;
|
||||||
@@ -48,6 +49,7 @@ export type IsValidParams = {
|
|||||||
isValidConnection?: IsValidConnection;
|
isValidConnection?: IsValidConnection;
|
||||||
doc: Document | ShadowRoot;
|
doc: Document | ShadowRoot;
|
||||||
lib: string;
|
lib: string;
|
||||||
|
flowId: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type XYHandleInstance = {
|
export type XYHandleInstance = {
|
||||||
@@ -79,6 +81,7 @@ function onPointerDown(
|
|||||||
nodes,
|
nodes,
|
||||||
lib,
|
lib,
|
||||||
autoPanOnConnect,
|
autoPanOnConnect,
|
||||||
|
flowId,
|
||||||
panBy,
|
panBy,
|
||||||
cancelConnection,
|
cancelConnection,
|
||||||
onConnectStart,
|
onConnectStart,
|
||||||
@@ -169,6 +172,7 @@ function onPointerDown(
|
|||||||
isValidConnection,
|
isValidConnection,
|
||||||
doc,
|
doc,
|
||||||
lib,
|
lib,
|
||||||
|
flowId,
|
||||||
});
|
});
|
||||||
|
|
||||||
handleDomNode = result.handleDomNode;
|
handleDomNode = result.handleDomNode;
|
||||||
@@ -251,12 +255,13 @@ function isValidHandle(
|
|||||||
fromType,
|
fromType,
|
||||||
doc,
|
doc,
|
||||||
lib,
|
lib,
|
||||||
|
flowId,
|
||||||
isValidConnection = alwaysValid,
|
isValidConnection = alwaysValid,
|
||||||
}: IsValidParams
|
}: IsValidParams
|
||||||
) {
|
) {
|
||||||
const isTarget = fromType === 'target';
|
const isTarget = fromType === 'target';
|
||||||
const handleDomNode = doc.querySelector(
|
const handleDomNode = doc.querySelector(
|
||||||
`.${lib}-flow__handle[data-id="${handle?.nodeId}-${handle?.id}-${handle?.type}"]`
|
`.${lib}-flow__handle[data-id="${flowId}-${handle?.nodeId}-${handle?.id}-${handle?.type}"]`
|
||||||
);
|
);
|
||||||
const { x, y } = getEventPosition(event);
|
const { x, y } = getEventPosition(event);
|
||||||
const handleBelow = doc.elementFromPoint(x, y);
|
const handleBelow = doc.elementFromPoint(x, y);
|
||||||
|
|||||||
Reference in New Issue
Block a user