Merge pull request #3716 from xyflow/next

Svelte Flow 0.0.29
This commit is contained in:
Moritz Klack
2023-12-13 12:47:18 +01:00
committed by GitHub
101 changed files with 2713 additions and 637 deletions
+14 -2
View File
@@ -44,7 +44,9 @@ import CancelConnection from '../examples/CancelConnection';
import InteractiveMinimap from '../examples/InteractiveMinimap'; import InteractiveMinimap from '../examples/InteractiveMinimap';
import UseOnSelectionChange from '../examples/UseOnSelectionChange'; import UseOnSelectionChange from '../examples/UseOnSelectionChange';
import NodeToolbar from '../examples/NodeToolbar'; import NodeToolbar from '../examples/NodeToolbar';
import useNodesInitialized from '../examples/UseNodesInit'; import UseNodesInitialized from '../examples/UseNodesInit';
import UseNodesData from '../examples/UseNodesData';
import UseHandleConnections from '../examples/UseHandleConnections';
export interface IRoute { export interface IRoute {
name: string; name: string;
@@ -261,7 +263,7 @@ const routes: IRoute[] = [
{ {
name: 'useNodesInitialized', name: 'useNodesInitialized',
path: 'use-nodes-initialized', path: 'use-nodes-initialized',
component: useNodesInitialized, component: UseNodesInitialized,
}, },
{ {
name: 'useOnSelectionChange', name: 'useOnSelectionChange',
@@ -273,6 +275,16 @@ const routes: IRoute[] = [
path: 'usereactflow', path: 'usereactflow',
component: UseReactFlow, component: UseReactFlow,
}, },
{
name: 'useHandleConnections',
path: 'usehandleconnections',
component: UseHandleConnections,
},
{
name: 'useNodesData',
path: 'usenodesdata',
component: UseNodesData,
},
{ {
name: 'useUpdateNodeInternals', name: 'useUpdateNodeInternals',
path: 'useupdatenodeinternals', path: 'useupdatenodeinternals',
@@ -15,6 +15,8 @@ import {
Position, Position,
} from '@xyflow/react'; } from '@xyflow/react';
import './style.css';
const nodeDefaults = { const nodeDefaults = {
sourcePosition: Position.Right, sourcePosition: Position.Right,
targetPosition: Position.Left, targetPosition: Position.Left,
@@ -1,4 +1,4 @@
import React, { memo, FC, CSSProperties, useCallback } from 'react'; import React, { memo, FC, CSSProperties, useCallback, useEffect } from 'react';
import { Handle, Position, NodeProps, Connection, Edge, useOnViewportChange, Viewport } from '@xyflow/react'; import { Handle, Position, NodeProps, Connection, Edge, useOnViewportChange, Viewport } from '@xyflow/react';
const targetHandleStyle: CSSProperties = { background: '#555' }; const targetHandleStyle: CSSProperties = { background: '#555' };
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { ReactFlow, Node, Edge, useNodesState, useEdgesState } from '@xyflow/react'; import { ReactFlow, Node, Edge, useNodesState, useEdgesState, ReactFlowProvider, useReactFlow } from '@xyflow/react';
import styles from './updatenode.module.css'; import styles from './updatenode.module.css';
@@ -13,6 +13,7 @@ const initialEdges: Edge[] = [{ id: 'e1-2', source: '1', target: '2' }];
const UpdateNode = () => { const UpdateNode = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const { updateNode } = useReactFlow();
const [nodeName, setNodeName] = useState<string>('Node 1'); const [nodeName, setNodeName] = useState<string>('Node 1');
const [nodeBg, setNodeBg] = useState<string>('#eee'); const [nodeBg, setNodeBg] = useState<string>('#eee');
@@ -80,9 +81,19 @@ const UpdateNode = () => {
<label>hidden:</label> <label>hidden:</label>
<input type="checkbox" checked={nodeHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} /> <input type="checkbox" checked={nodeHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} />
</div> </div>
<button
onClick={() => updateNode('1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }))}
>
update position
</button>
</div> </div>
</ReactFlow> </ReactFlow>
); );
}; };
export default UpdateNode; export default () => (
<ReactFlowProvider>
<UpdateNode />
</ReactFlowProvider>
);
@@ -0,0 +1,39 @@
import { memo, FC, useEffect, useCallback } from 'react';
import { Handle, Position, NodeProps, useHandleConnections, Connection, HandleComponentProps } from '@xyflow/react';
function CustomHandle({ nodeId, ...handleProps }: HandleComponentProps & { nodeId: string }) {
const onConnect = useCallback(
(connections: Connection[]) => console.log('onConnect handler, node id:', nodeId, connections),
[nodeId]
);
const onDisconnect = useCallback(
(connections: Connection[]) => console.log('onDisconnect handler, node id:', nodeId, connections),
[nodeId]
);
const connections = useHandleConnections({
handleType: handleProps.type,
handleId: handleProps.id,
onConnect,
onDisconnect,
});
useEffect(() => {
console.log('useEffect, node id:', nodeId, handleProps.type, connections);
}, [connections]);
return <Handle {...handleProps} />;
}
const CustomNode: FC<NodeProps> = ({ id }) => {
return (
<div style={{ background: '#333', color: '#fff', padding: 10, fontSize: 12, borderRadius: 10 }}>
<CustomHandle nodeId={id} type="target" position={Position.Left} />
<div>node {id}</div>
<CustomHandle nodeId={id} type="source" position={Position.Right} id="a" style={{ top: 10 }} />
<CustomHandle nodeId={id} type="source" position={Position.Right} id="b" style={{ top: 20 }} />
</div>
);
};
export default memo(CustomNode);
@@ -0,0 +1,41 @@
import { memo, FC, useEffect, useCallback } from 'react';
import { Handle, Position, NodeProps, useHandleConnections, Connection, HandleComponentProps } from '@xyflow/react';
function CustomHandle({ nodeId, ...handleProps }: HandleComponentProps & { nodeId: string }) {
const onConnect = useCallback(
(connections: Connection[]) => {
console.log('onConnect handler, node id:', nodeId, connections);
},
[nodeId]
);
const onDisconnect = useCallback(
(connections: Connection[]) => {
console.log('onDisconnect handler, node id:', nodeId, connections);
},
[nodeId]
);
const connections = useHandleConnections({
handleType: handleProps.type,
handleId: handleProps.id,
onConnect,
onDisconnect,
});
useEffect(() => {
console.log('useEffect, node id:', nodeId, handleProps.type, connections);
}, [connections]);
return <Handle {...handleProps} />;
}
const CustomNode: FC<NodeProps> = ({ id }) => {
return (
<div style={{ background: '#333', color: '#fff', padding: 10, fontSize: 12, borderRadius: 10 }}>
<CustomHandle nodeId={id} type="target" position={Position.Left} />
<div>node {id}</div>
<CustomHandle nodeId={id} type="source" position={Position.Right} />
</div>
);
};
export default memo(CustomNode);
@@ -0,0 +1,118 @@
import { useCallback } from 'react';
import {
ReactFlow,
MiniMap,
Controls,
addEdge,
Connection,
useNodesState,
useEdgesState,
Background,
} from '@xyflow/react';
import MultiHandleNode from './MultiHandleNode';
import SingleHandleNode from './SingleHandleNode';
const nodeTypes = {
multi: MultiHandleNode,
single: SingleHandleNode,
};
const initNodes = [
{
id: '1',
type: 'single',
data: {},
position: { x: 0, y: 0 },
},
{
id: '2',
type: 'single',
data: {},
position: { x: 200, y: -100 },
},
{
id: '3',
type: 'single',
data: {},
position: { x: 200, y: 100 },
},
{
id: '4',
type: 'multi',
data: {},
position: { x: 400, y: 0 },
},
{
id: '5',
type: 'multi',
data: {},
position: { x: 600, y: -100 },
},
{
id: '6',
type: 'multi',
data: {},
position: { x: 600, y: 100 },
},
];
const initEdges = [
{
id: 'e1-2',
source: '1',
target: '2',
},
{
id: 'e1-3',
source: '1',
target: '3',
},
{
id: 'e4a-5',
source: '4',
sourceHandle: 'a',
target: '5',
},
{
id: 'e4b-5',
source: '4',
sourceHandle: 'b',
target: '6',
},
];
const defaultEdgeOptions = {
animated: true,
};
const CustomNodeFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges);
const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
fitView
minZoom={0.3}
maxZoom={2}
colorMode="dark"
defaultEdgeOptions={defaultEdgeOptions}
>
<MiniMap />
<Controls />
<Background />
</ReactFlow>
);
};
export default CustomNodeFlow;
@@ -0,0 +1,22 @@
import { memo } from 'react';
import { Handle, Position, useHandleConnections, useNodesData } from '@xyflow/react';
function ResultNode() {
const connections = useHandleConnections({
type: 'target',
});
const nodesData = useNodesData(connections.map((connection) => connection.source));
return (
<div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}>
<Handle type="target" position={Position.Left} />
<div>
incoming texts:{' '}
{nodesData?.filter((nodeData) => nodeData.text !== undefined).map(({ text }, i) => <div key={i}>{text}</div>) ||
'none'}
</div>
</div>
);
}
export default memo(ResultNode);
@@ -0,0 +1,20 @@
import { memo, ChangeEventHandler } from 'react';
import { Position, NodeProps, Handle, useReactFlow } from '@xyflow/react';
function TextNode({ id, data }: NodeProps) {
const { updateNodeData } = useReactFlow();
const onChange: ChangeEventHandler<HTMLInputElement> = (evt) => updateNodeData(id, { text: evt.target.value });
return (
<div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}>
<div>node {id}</div>
<div>
<input onChange={onChange} value={data.text} />
</div>
<Handle type="source" position={Position.Right} />
</div>
);
}
export default memo(TextNode);
@@ -0,0 +1,24 @@
import { memo, useEffect } from 'react';
import { Position, NodeProps, useReactFlow, Handle, useHandleConnections, useNodesData } from '@xyflow/react';
function UppercaseNode({ id }: NodeProps) {
const { updateNodeData } = useReactFlow();
const connections = useHandleConnections({
type: 'target',
});
const nodeData = useNodesData(connections[0]?.source);
useEffect(() => {
updateNodeData(id, { text: nodeData?.text.toUpperCase() });
}, [nodeData]);
return (
<div style={{ background: '#eee', color: '#222', padding: 10, fontSize: 12, borderRadius: 10 }}>
<Handle type="target" position={Position.Left} isConnectable={connections.length === 0} />
<div>uppercase transform</div>
<Handle type="source" position={Position.Right} />
</div>
);
}
export default memo(UppercaseNode);
@@ -0,0 +1,102 @@
import { useCallback } from 'react';
import {
ReactFlow,
Controls,
addEdge,
Connection,
useNodesState,
useEdgesState,
Background,
Node,
Edge,
} from '@xyflow/react';
import TextNode from './TextNode';
import ResultNode from './ResultNode';
import UppercaseNode from './UppercaseNode';
export type TextNode = Node<{ text: string }, 'text'>;
export type ResultNode = Node<{}, 'result'>;
export type UppercaseNode = Node<{}, 'uppercase'>;
export type MyNode = Node<{ text: string }, 'text'> | Node<{}, 'result'> | Node<{}, 'uppercase'>;
const nodeTypes = {
text: TextNode,
result: ResultNode,
uppercase: UppercaseNode,
};
const initNodes: MyNode[] = [
{
id: '1',
type: 'text',
data: {
text: 'hello',
},
position: { x: -100, y: -50 },
},
{
id: '1a',
type: 'uppercase',
data: {},
position: { x: 100, y: 0 },
},
{
id: '2',
type: 'text',
data: {
text: 'world',
},
position: { x: 0, y: 100 },
},
{
id: '3',
type: 'result',
data: {},
position: { x: 300, y: 50 },
},
];
const initEdges: Edge[] = [
{
id: 'e1-1a',
source: '1',
target: '1a',
},
{
id: 'e1a-3',
source: '1a',
target: '3',
},
{
id: 'e2-3',
source: '2',
target: '3',
},
];
const CustomNodeFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initEdges);
const onConnect = useCallback((connection: Connection) => setEdges((eds) => addEdge(connection, eds)), [setEdges]);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
nodeTypes={nodeTypes}
fitView
>
<Controls />
<Background />
</ReactFlow>
);
};
export default CustomNodeFlow;
@@ -4,13 +4,14 @@
const routes = [ const routes = [
'add-node-on-drop', 'add-node-on-drop',
'colormode', 'color-mode',
'custom-connection-line', 'custom-connection-line',
'customnode', 'customnode',
'dagre', 'dagre',
'drag-n-drop', 'drag-n-drop',
'edges', 'edges',
'figma', 'figma',
'handle-connect',
'interaction', 'interaction',
'intersections', 'intersections',
'node-toolbar', 'node-toolbar',
@@ -18,6 +19,7 @@
'stress', 'stress',
'subflows', 'subflows',
'two-way-viewport', 'two-way-viewport',
'usenodesdata',
'usesvelteflow', 'usesvelteflow',
'useupdatenodeinternals', 'useupdatenodeinternals',
'validation' 'validation'
@@ -1,6 +1,12 @@
<script lang="ts"> <script lang="ts">
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
import { SvelteFlow, useSvelteFlow, type Edge, type Node } from '@xyflow/svelte'; import {
SvelteFlow,
useSvelteFlow,
type Edge,
type Node,
type OnConnectEnd
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css'; import '@xyflow/svelte/dist/style.css';
@@ -16,16 +22,18 @@
const nodes = writable<Node[]>(initialNodes); const nodes = writable<Node[]>(initialNodes);
const edges = writable<Edge[]>([]); const edges = writable<Edge[]>([]);
let connectingNodeId: string = '0'; let connectingNodeId: string | null = '0';
let rect: DOMRectReadOnly; let rect: DOMRectReadOnly;
let id = 1; let id = 1;
const getId = () => `${id++}`; const getId = () => `${id++}`;
const { screenToFlowPosition, flowToScreenPosition } = useSvelteFlow(); const { screenToFlowPosition, flowToScreenPosition } = useSvelteFlow();
function handleConnectEnd({ detail: { event } }: { detail: { event: MouseEvent | TouchEvent } }) { const handleConnectEnd: OnConnectEnd = (event) => {
if (!connectingNodeId) return;
// See of connection landed inside the flow pane // See of connection landed inside the flow pane
const targetIsPane = event.target?.classList.contains('svelte-flow__pane'); const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('svelte-flow__pane');
if (targetIsPane) { if (targetIsPane) {
const id = getId(); const id = getId();
const position = { const position = {
@@ -58,7 +66,7 @@
$nodes = $nodes; $nodes = $nodes;
$edges = $edges; $edges = $edges;
} }
} };
</script> </script>
<svelte:window /> <svelte:window />
@@ -69,11 +77,11 @@
{edges} {edges}
fitView fitView
fitViewOptions={{ padding: 2 }} fitViewOptions={{ padding: 2 }}
on:connectstart={({ detail: { nodeId } }) => { onconnectstart={(_, { nodeId }) => {
// Memorize the nodeId you start draggin a connection line from a node // Memorize the nodeId you start draggin a connection line from a node
connectingNodeId = nodeId; connectingNodeId = nodeId;
}} }}
on:connectend={handleConnectEnd} onconnectend={handleConnectEnd}
/> />
</div> </div>
@@ -85,9 +85,9 @@
{nodes} {nodes}
{edges} {edges}
{nodeTypes} {nodeTypes}
style="--background-color: {$bgColor}" style="--xy-background-color: {$bgColor}"
fitView fitView
on:connect={onConnect} onconnect={onConnect}
> >
<Controls /> <Controls />
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
@@ -10,7 +10,7 @@
</script> </script>
<div class="custom"> <div class="custom">
<Handle type="target" position={Position.Left} on:connect /> <Handle type="target" position={Position.Left} />
<div> <div>
Custom Color Picker Node: <strong>{$colorStore}</strong> Custom Color Picker Node: <strong>{$colorStore}</strong>
</div> </div>
@@ -20,14 +20,8 @@
on:input={(evt) => colorStore.set(evt.currentTarget.value)} on:input={(evt) => colorStore.set(evt.currentTarget.value)}
value={$colorStore} value={$colorStore}
/> />
<Handle type="source" position={Position.Right} id="a" style="top: 20px;" on:connect /> <Handle type="source" position={Position.Right} id="a" style="top: 20px;" />
<Handle <Handle type="source" position={Position.Right} id="b" style="top: auto; bottom: 10px;" />
type="source"
position={Position.Right}
id="b"
style="top: auto; bottom: 10px;"
on:connect
/>
</div> </div>
<style> <style>
@@ -6,10 +6,13 @@
Background, Background,
BackgroundVariant, BackgroundVariant,
MiniMap, MiniMap,
MarkerType MarkerType,
type Connection
} from '@xyflow/svelte'; } from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css'; import '@xyflow/svelte/dist/style.css';
import ButtonEdge from './ButtonEdge.svelte';
import CustomBezierEdge from './CustomBezierEdge.svelte';
const nodes = writable([ const nodes = writable([
{ {
@@ -110,13 +113,14 @@
id: 'e5-8', id: 'e5-8',
source: '5', source: '5',
target: '8', target: '8',
data: { text: 'custom edge' } type: 'button'
}, },
{ {
id: 'e5-9', id: 'e5-9',
source: '5', source: '5',
target: '9', target: '9',
data: { text: 'custom edge 2' } type: 'customBezier',
label: 'custom bezier'
}, },
{ {
id: 'e5-6', id: 'e5-6',
@@ -143,9 +147,34 @@
} }
} }
]); ]);
const edgeTypes = {
button: ButtonEdge,
customBezier: CustomBezierEdge
};
function getEdgeId(connection: Connection) {
return `edge-${connection.source}-${connection.target}}`;
}
$: console.log('edges', $edges);
</script> </script>
<SvelteFlow {nodes} {edges} fitView nodeDragThreshold={2}> <SvelteFlow
{nodes}
{edges}
{edgeTypes}
fitView
nodeDragThreshold={2}
onedgecreate={(connection) => {
console.log('on edge create', connection);
return {
...connection,
id: getEdgeId(connection)
};
}}
>
<Controls /> <Controls />
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
<MiniMap /> <MiniMap />
@@ -0,0 +1,92 @@
<script lang="ts">
import { getBezierPath, BaseEdge, type EdgeProps, EdgeLabelRenderer } from '@xyflow/svelte';
type $$Props = EdgeProps;
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition
});
source;
target;
animated;
selected;
data;
label;
labelStyle;
markerStart;
interactionWidth;
sourceHandleId;
targetHandleId;
</script>
<BaseEdge path={edgePath} {markerEnd} {style} />
<EdgeLabelRenderer>
<div
class="edgeButtonContainer nodrag nopan"
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
>
<button
class="edgeButton"
on:click={(event) => {
event.stopPropagation();
alert(`remove ${id}`);
}}
>
×
</button>
</div>
</EdgeLabelRenderer>
<style>
.edgeButtonContainer {
position: absolute;
font-size: 12pt;
/* everything inside EdgeLabelRenderer has no pointer events by default */
/* if you have an interactive element, set pointer-events: all */
pointer-events: all;
}
.edgeButton {
width: 20px;
height: 20px;
background: #eee;
border: 1px solid #fff;
cursor: pointer;
border-radius: 50%;
font-size: 12px;
line-height: 1;
}
.edgeButton:hover {
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.08);
}
</style>
@@ -0,0 +1,55 @@
<script lang="ts">
import { BezierEdge, type EdgeProps } from '@xyflow/svelte';
type $$Props = EdgeProps;
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
id;
source;
target;
animated;
selected;
data;
sourcePosition;
targetPosition;
sourceHandleId;
targetHandleId;
</script>
<BezierEdge
{sourceX}
{sourceY}
{sourcePosition}
{targetX}
{targetY}
{targetPosition}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{style}
{interactionWidth}
pathOptions={{ curvature: 1 }}
/>
@@ -0,0 +1,94 @@
<script lang="ts">
import { writable } from 'svelte/store';
import {
SvelteFlow,
Controls,
Background,
BackgroundVariant,
MiniMap,
type Node,
type NodeTypes,
type Edge
} from '@xyflow/svelte';
import SingleHandleNode from './SingleHandleNode.svelte';
import MultiHandleNode from './MultiHandleNode.svelte';
import '@xyflow/svelte/dist/style.css';
const nodeTypes: NodeTypes = {
single: SingleHandleNode,
multi: MultiHandleNode
};
const nodes = writable<Node[]>([
{
id: '1',
type: 'single',
data: {},
position: { x: 0, y: 0 }
},
{
id: '2',
type: 'single',
data: {},
position: { x: 200, y: -100 }
},
{
id: '3',
type: 'single',
data: {},
position: { x: 200, y: 100 }
},
{
id: '4',
type: 'multi',
data: {},
position: { x: 400, y: 0 }
},
{
id: '5',
type: 'multi',
data: {},
position: { x: 600, y: -100 }
},
{
id: '6',
type: 'multi',
data: {},
position: { x: 600, y: 100 }
}
]);
const edges = writable<Edge[]>([
{
id: 'e1-2',
source: '1',
target: '2'
},
{
id: 'e1-3',
source: '1',
target: '3'
},
{
id: 'e4a-5',
source: '4',
sourceHandle: 'a',
target: '5'
},
{
id: 'e4b-5',
source: '4',
sourceHandle: 'b',
target: '6'
}
]);
</script>
<SvelteFlow {nodes} {edges} {nodeTypes} fitView colorMode="dark">
<Controls />
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
</SvelteFlow>
@@ -0,0 +1,110 @@
<script lang="ts">
import {
Handle,
Position,
type NodeProps,
type Connection,
useHandleConnections
} from '@xyflow/svelte';
type $$Props = NodeProps;
export let id: $$Props['id'];
function onConnectTarget(connection: Connection[]) {
console.log('connect target', connection);
}
function onConnectSource(handleId: string, connection: Connection[]) {
console.log('connect source', handleId, connection);
}
function onDisconnectTarget(connection: Connection[]) {
console.log('disconnect target', connection);
}
function onDisconnectSource(handleId: string, connection: Connection[]) {
console.log('disconnect source', handleId, connection);
}
const connections = useHandleConnections({ nodeId: id, type: 'target' });
$: {
console.log('connections', id, $connections);
}
export let data: $$Props['data'];
export let targetPosition: $$Props['targetPosition'] = Position.Top;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let type: $$Props['type'] = undefined;
export let zIndex: $$Props['zIndex'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsolute: $$Props['positionAbsolute'] = {
x: 0,
y: 0
};
export let isConnectable: $$Props['isConnectable'] = undefined;
data;
targetPosition;
sourcePosition;
width;
height;
selected;
type;
zIndex;
dragging;
dragHandle;
positionAbsolute;
isConnectable;
</script>
<div class="custom">
<Handle
type="target"
position={Position.Left}
onconnect={onConnectTarget}
ondisconnect={onDisconnectTarget}
/>
<div>node {id}</div>
<Handle
id="a"
type="source"
position={Position.Right}
onconnect={(connections) => onConnectSource('a', connections)}
ondisconnect={(connections) => onDisconnectSource('a', connections)}
class="source-a"
/>
<Handle
id="b"
type="source"
position={Position.Right}
onconnect={(connections) => onConnectSource('b', connections)}
ondisconnect={(connections) => onDisconnectSource('b', connections)}
class="source-b"
/>
</div>
<style>
.custom {
background-color: #333;
padding: 10px;
border-radius: 10px;
color: #fff;
}
.custom :global(.source-a) {
top: 5px;
transform: translate(50%, 0);
}
.custom :global(.source-b) {
bottom: 5px;
top: auto;
transform: translate(50%, 0);
}
</style>
@@ -0,0 +1,77 @@
<script lang="ts">
import { Handle, Position, type NodeProps, type Connection } from '@xyflow/svelte';
type $$Props = NodeProps;
export let id: $$Props['id'];
function onConnectTarget(connection: Connection[]) {
console.log('connect target', connection);
}
function onConnectSource(connection: Connection[]) {
console.log('connect source', connection);
}
function onDisconnectTarget(connection: Connection[]) {
console.log('disconnect target', connection);
}
function onDisconnectSource(connection: Connection[]) {
console.log('disconnect source', connection);
}
export let data: $$Props['data'];
export let targetPosition: $$Props['targetPosition'] = Position.Top;
export let sourcePosition: $$Props['sourcePosition'] = Position.Bottom;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let type: $$Props['type'] = undefined;
export let zIndex: $$Props['zIndex'] = undefined;
export let dragging: $$Props['dragging'] = false;
export let dragHandle: $$Props['dragHandle'] = undefined;
export let positionAbsolute: $$Props['positionAbsolute'] = {
x: 0,
y: 0
};
export let isConnectable: $$Props['isConnectable'] = undefined;
data;
targetPosition;
sourcePosition;
width;
height;
selected;
type;
zIndex;
dragging;
dragHandle;
positionAbsolute;
isConnectable;
</script>
<div class="custom">
<Handle
type="target"
position={Position.Left}
onconnect={onConnectTarget}
ondisconnect={onDisconnectTarget}
/>
<div>node {id}</div>
<Handle
type="source"
position={Position.Right}
onconnect={onConnectSource}
ondisconnect={onDisconnectSource}
/>
</div>
<style>
.custom {
background-color: #333;
padding: 10px;
border-radius: 10px;
color: #fff;
}
</style>
@@ -12,7 +12,8 @@
type EdgeTypes, type EdgeTypes,
type Node, type Node,
type Edge, type Edge,
ConnectionMode ConnectionMode,
useSvelteFlow
} from '@xyflow/svelte'; } from '@xyflow/svelte';
import CustomNode from './CustomNode.svelte'; import CustomNode from './CustomNode.svelte';
@@ -150,9 +151,9 @@
on:nodemouseenter={(event) => console.log('on node enter', event)} on:nodemouseenter={(event) => console.log('on node enter', event)}
on:nodemouseleave={(event) => console.log('on node leave', event)} on:nodemouseleave={(event) => console.log('on node leave', event)}
on:edgeclick={(event) => console.log('edge click', event)} on:edgeclick={(event) => console.log('edge click', event)}
on:connectstart={(event) => console.log('on connect start', event)} onconnectstart={(event) => console.log('on connect start', event)}
on:connect={(event) => console.log('on connect', event)} onconnect={(event) => console.log('on connect', event)}
on:connectend={(event) => console.log('on connect end', event)} onconnectend={(event) => console.log('on connect end', event)}
on:paneclick={(event) => console.log('on pane click', event)} on:paneclick={(event) => console.log('on pane click', event)}
on:panecontextmenu={(event) => { on:panecontextmenu={(event) => {
console.log('on pane contextmenu', event); console.log('on pane contextmenu', event);
@@ -0,0 +1,80 @@
<script lang="ts">
import { writable } from 'svelte/store';
import {
SvelteFlow,
Controls,
Background,
BackgroundVariant,
MiniMap,
type Node,
type NodeTypes,
type Edge
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import TextNode from './TextNode.svelte';
import UppercaseNode from './UppercaseNode.svelte';
import ResultNode from './ResultNode.svelte';
const nodeTypes: NodeTypes = {
text: TextNode,
uppercase: UppercaseNode,
result: ResultNode
};
const nodes = writable<Node[]>([
{
id: '1',
type: 'text',
data: {
text: 'hello'
},
position: { x: -100, y: -50 }
},
{
id: '1a',
type: 'uppercase',
data: {},
position: { x: 100, y: 0 }
},
{
id: '2',
type: 'text',
data: {
text: 'world'
},
position: { x: 0, y: 100 }
},
{
id: '3',
type: 'result',
data: {},
position: { x: 300, y: 50 }
}
]);
const edges = writable<Edge[]>([
{
id: 'e1-1a',
source: '1',
target: '1a'
},
{
id: 'e1a-3',
source: '1a',
target: '3'
},
{
id: 'e2-3',
source: '2',
target: '3'
}
]);
</script>
<SvelteFlow {nodes} {edges} {nodeTypes} fitView>
<Controls />
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
</SvelteFlow>
@@ -0,0 +1,37 @@
<script lang="ts">
import {
Handle,
Position,
useHandleConnections,
useNodesData,
type NodeProps
} from '@xyflow/svelte';
type $$Props = NodeProps;
export let id: $$Props['id'];
const connections = useHandleConnections({
nodeId: id,
type: 'target'
});
$: nodeData = useNodesData($connections.map((connection) => connection.source));
</script>
<div class="custom">
<Handle type="target" position={Position.Left} />
<div>incoming texts:</div>
{#each $nodeData as data}
<div>{data.text}</div>
{/each}
</div>
<style>
.custom {
background-color: #eee;
padding: 10px;
border-radius: 10px;
}
</style>
@@ -0,0 +1,29 @@
<script lang="ts">
import { Handle, Position, type NodeProps, useSvelteFlow } from '@xyflow/svelte';
type $$Props = NodeProps;
export let id: $$Props['id'];
export let data: $$Props['data'];
const { updateNodeData } = useSvelteFlow();
</script>
<div class="custom">
<div>node {id}</div>
<div>
<input
value={data.text}
on:input={(evt) => updateNodeData(id, { text: evt.currentTarget.value })}
/>
</div>
<Handle type="source" position={Position.Right} />
</div>
<style>
.custom {
background-color: #eee;
padding: 10px;
border-radius: 10px;
}
</style>
@@ -0,0 +1,40 @@
<script lang="ts">
import {
Handle,
Position,
useHandleConnections,
useNodesData,
useSvelteFlow,
type NodeProps
} from '@xyflow/svelte';
type $$Props = NodeProps;
export let id: $$Props['id'];
const { updateNodeData } = useSvelteFlow();
const connections = useHandleConnections({
nodeId: id,
type: 'target'
});
$: nodeData = useNodesData($connections[0]?.source);
$: {
updateNodeData(id, { text: $nodeData?.text?.toUpperCase() || '' });
}
</script>
<div class="custom">
<Handle type="target" position={Position.Left} isConnectable={$connections.length === 0} />
<div>uppercase transform</div>
<Handle type="source" position={Position.Right} />
</div>
<style>
.custom {
background-color: #eee;
padding: 10px;
border-radius: 10px;
}
</style>
@@ -15,15 +15,9 @@
}; };
</script> </script>
<Handle type="target" position={Position.Top} on:connect /> <Handle type="target" position={Position.Top} />
<button on:click={onClick}>add handle</button> <button on:click={onClick}>add handle</button>
{#each Array.from({ length: handleCount }) as handle, i} {#each Array.from({ length: handleCount }) as handle, i}
<Handle <Handle type="source" position={Position.Bottom} id={`${i}`} style={`left: ${i * 10}px;`} />
type="source"
position={Position.Bottom}
id={`${i}`}
style={`left: ${i * 10}px;`}
on:connect
/>
{/each} {/each}
@@ -6,7 +6,9 @@
Background, Background,
BackgroundVariant, BackgroundVariant,
MiniMap, MiniMap,
type NodeTypes type NodeTypes,
useSvelteFlow,
Panel
} from '@xyflow/svelte'; } from '@xyflow/svelte';
import CustomNode from './CustomNode.svelte'; import CustomNode from './CustomNode.svelte';
@@ -50,6 +52,12 @@
target: '3' target: '3'
} }
]); ]);
const { updateNode } = useSvelteFlow();
const updateNodePosition = () => {
updateNode('1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));
};
</script> </script>
<main> <main>
@@ -57,6 +65,8 @@
<Controls /> <Controls />
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
<MiniMap /> <MiniMap />
<Panel><button on:click={updateNodePosition}>update node</button></Panel>
</SvelteFlow> </SvelteFlow>
</main> </main>
@@ -55,8 +55,8 @@ function Background({
{ {
...style, ...style,
...containerStyle, ...containerStyle,
'--background-color-props': bgColor, '--xy-background-color-props': bgColor,
'--background-pattern-color-props': color, '--xy-background-pattern-color-props': color,
} as CSSProperties } as CSSProperties
} }
ref={ref} ref={ref}
@@ -129,10 +129,10 @@ function MiniMap({
style={ style={
{ {
...style, ...style,
'--minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined, '--xy-minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
'--minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined, '--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
'--minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined, '--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
'--minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined, '--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
} as CSSProperties } as CSSProperties
} }
className={cc(['react-flow__minimap', className])} className={cc(['react-flow__minimap', className])}
@@ -4,56 +4,67 @@ import { Position, getBezierPath } from '@xyflow/system';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import type { BezierEdgeProps } from '../../types'; import type { BezierEdgeProps } from '../../types';
const BezierEdge = memo( function createBezierEdge(params: { isInternal: boolean }) {
({ // eslint-disable-next-line react/display-name
sourceX, return memo(
sourceY, ({
targetX, id,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: BezierEdgeProps) => {
const [path, labelX, labelY] = getBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
targetPosition, sourcePosition = Position.Bottom,
curvature: pathOptions?.curvature, targetPosition = Position.Top,
}); label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: BezierEdgeProps) => {
const [path, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: pathOptions?.curvature,
});
return ( const _id = params.isInternal ? undefined : id;
<BaseEdge
path={path} return (
labelX={labelX} <BaseEdge
labelY={labelY} id={_id}
label={label} path={path}
labelStyle={labelStyle} labelX={labelX}
labelShowBg={labelShowBg} labelY={labelY}
labelBgStyle={labelBgStyle} label={label}
labelBgPadding={labelBgPadding} labelStyle={labelStyle}
labelBgBorderRadius={labelBgBorderRadius} labelShowBg={labelShowBg}
style={style} labelBgStyle={labelBgStyle}
markerEnd={markerEnd} labelBgPadding={labelBgPadding}
markerStart={markerStart} labelBgBorderRadius={labelBgBorderRadius}
interactionWidth={interactionWidth} style={style}
/> markerEnd={markerEnd}
); markerStart={markerStart}
} interactionWidth={interactionWidth}
); />
);
}
);
}
const BezierEdge = createBezierEdge({ isInternal: false });
const BezierEdgeInternal = createBezierEdge({ isInternal: true });
BezierEdge.displayName = 'BezierEdge'; BezierEdge.displayName = 'BezierEdge';
BezierEdgeInternal.displayName = 'BezierEdgeInternal';
export default BezierEdge; export { BezierEdge, BezierEdgeInternal };
@@ -2,7 +2,7 @@ import { memo } from 'react';
import { Position, getBezierEdgeCenter } from '@xyflow/system'; import { Position, getBezierEdgeCenter } from '@xyflow/system';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types'; import type { SimpleBezierEdgeProps } from '../../types';
export interface GetSimpleBezierPathParams { export interface GetSimpleBezierPathParams {
sourceX: number; sourceX: number;
@@ -71,54 +71,65 @@ export function getSimpleBezierPath({
]; ];
} }
const SimpleBezierEdge = memo( function createSimpleBezierEdge(params: { isInternal: boolean }) {
({ // eslint-disable-next-line react/display-name
sourceX, return memo(
sourceY, ({
targetX, id,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: EdgeProps) => {
const [path, labelX, labelY] = getSimpleBezierPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
targetPosition, sourcePosition = Position.Bottom,
}); targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: SimpleBezierEdgeProps) => {
const [path, labelX, labelY] = getSimpleBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
return ( const _id = params.isInternal ? undefined : id;
<BaseEdge
path={path} return (
labelX={labelX} <BaseEdge
labelY={labelY} id={_id}
label={label} path={path}
labelStyle={labelStyle} labelX={labelX}
labelShowBg={labelShowBg} labelY={labelY}
labelBgStyle={labelBgStyle} label={label}
labelBgPadding={labelBgPadding} labelStyle={labelStyle}
labelBgBorderRadius={labelBgBorderRadius} labelShowBg={labelShowBg}
style={style} labelBgStyle={labelBgStyle}
markerEnd={markerEnd} labelBgPadding={labelBgPadding}
markerStart={markerStart} labelBgBorderRadius={labelBgBorderRadius}
interactionWidth={interactionWidth} style={style}
/> markerEnd={markerEnd}
); markerStart={markerStart}
} interactionWidth={interactionWidth}
); />
);
}
);
}
const SimpleBezierEdge = createSimpleBezierEdge({ isInternal: false });
const SimpleBezierEdgeInternal = createSimpleBezierEdge({ isInternal: true });
SimpleBezierEdge.displayName = 'SimpleBezierEdge'; SimpleBezierEdge.displayName = 'SimpleBezierEdge';
SimpleBezierEdgeInternal.displayName = 'SimpleBezierEdgeInternal';
export default SimpleBezierEdge; export { SimpleBezierEdge, SimpleBezierEdgeInternal };
@@ -4,57 +4,68 @@ import { Position, getSmoothStepPath } from '@xyflow/system';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import type { SmoothStepEdgeProps } from '../../types'; import type { SmoothStepEdgeProps } from '../../types';
const SmoothStepEdge = memo( function createSmoothStepEdge(params: { isInternal: boolean }) {
({ // eslint-disable-next-line react/display-name
sourceX, return memo(
sourceY, ({
targetX, id,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: SmoothStepEdgeProps) => {
const [path, labelX, labelY] = getSmoothStepPath({
sourceX, sourceX,
sourceY, sourceY,
sourcePosition,
targetX, targetX,
targetY, targetY,
targetPosition, label,
borderRadius: pathOptions?.borderRadius, labelStyle,
offset: pathOptions?.offset, labelShowBg,
}); labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: SmoothStepEdgeProps) => {
const [path, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset,
});
return ( const _id = params.isInternal ? undefined : id;
<BaseEdge
path={path} return (
labelX={labelX} <BaseEdge
labelY={labelY} id={_id}
label={label} path={path}
labelStyle={labelStyle} labelX={labelX}
labelShowBg={labelShowBg} labelY={labelY}
labelBgStyle={labelBgStyle} label={label}
labelBgPadding={labelBgPadding} labelStyle={labelStyle}
labelBgBorderRadius={labelBgBorderRadius} labelShowBg={labelShowBg}
style={style} labelBgStyle={labelBgStyle}
markerEnd={markerEnd} labelBgPadding={labelBgPadding}
markerStart={markerStart} labelBgBorderRadius={labelBgBorderRadius}
interactionWidth={interactionWidth} style={style}
/> markerEnd={markerEnd}
); markerStart={markerStart}
} interactionWidth={interactionWidth}
); />
);
}
);
}
const SmoothStepEdge = createSmoothStepEdge({ isInternal: false });
const SmoothStepEdgeInternal = createSmoothStepEdge({ isInternal: true });
SmoothStepEdge.displayName = 'SmoothStepEdge'; SmoothStepEdge.displayName = 'SmoothStepEdge';
SmoothStepEdgeInternal.displayName = 'SmoothStepEdgeInternal';
export default SmoothStepEdge; export { SmoothStepEdge, SmoothStepEdgeInternal };
@@ -1,15 +1,30 @@
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import SmoothStepEdge from './SmoothStepEdge'; import { SmoothStepEdge } from './SmoothStepEdge';
import type { SmoothStepEdgeProps } from '../../types'; import type { StepEdgeProps } from '../../types';
const StepEdge = memo((props: SmoothStepEdgeProps) => ( function createStepEdge(params: { isInternal: boolean }) {
<SmoothStepEdge // eslint-disable-next-line react/display-name
{...props} return memo(({ id, ...props }: StepEdgeProps) => {
pathOptions={useMemo(() => ({ borderRadius: 0, offset: props.pathOptions?.offset }), [props.pathOptions?.offset])} const _id = params.isInternal ? undefined : id;
/>
)); return (
<SmoothStepEdge
{...props}
id={_id}
pathOptions={useMemo(
() => ({ borderRadius: 0, offset: props.pathOptions?.offset }),
[props.pathOptions?.offset]
)}
/>
);
});
}
const StepEdge = createStepEdge({ isInternal: false });
const StepEdgeInternal = createStepEdge({ isInternal: true });
StepEdge.displayName = 'StepEdge'; StepEdge.displayName = 'StepEdge';
StepEdgeInternal.displayName = 'StepEdgeInternal';
export default StepEdge; export { StepEdge, StepEdgeInternal };
@@ -2,47 +2,58 @@ import { memo } from 'react';
import { getStraightPath } from '@xyflow/system'; import { getStraightPath } from '@xyflow/system';
import BaseEdge from './BaseEdge'; import BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types'; import type { StraightEdgeProps } from '../../types';
const StraightEdge = memo( function createStraightEdge(params: { isInternal: boolean }) {
({ // eslint-disable-next-line react/display-name
sourceX, return memo(
sourceY, ({
targetX, id,
targetY, sourceX,
label, sourceY,
labelStyle, targetX,
labelShowBg, targetY,
labelBgStyle, label,
labelBgPadding, labelStyle,
labelBgBorderRadius, labelShowBg,
style, labelBgStyle,
markerEnd, labelBgPadding,
markerStart, labelBgBorderRadius,
interactionWidth, style,
}: EdgeProps) => { markerEnd,
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY }); markerStart,
interactionWidth,
}: StraightEdgeProps) => {
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
return ( const _id = params.isInternal ? undefined : id;
<BaseEdge
path={path} return (
labelX={labelX} <BaseEdge
labelY={labelY} id={_id}
label={label} path={path}
labelStyle={labelStyle} labelX={labelX}
labelShowBg={labelShowBg} labelY={labelY}
labelBgStyle={labelBgStyle} label={label}
labelBgPadding={labelBgPadding} labelStyle={labelStyle}
labelBgBorderRadius={labelBgBorderRadius} labelShowBg={labelShowBg}
style={style} labelBgStyle={labelBgStyle}
markerEnd={markerEnd} labelBgPadding={labelBgPadding}
markerStart={markerStart} labelBgBorderRadius={labelBgBorderRadius}
interactionWidth={interactionWidth} style={style}
/> markerEnd={markerEnd}
); markerStart={markerStart}
} interactionWidth={interactionWidth}
); />
);
}
);
}
const StraightEdge = createStraightEdge({ isInternal: false });
const StraightEdgeInternal = createStraightEdge({ isInternal: true });
StraightEdge.displayName = 'StraightEdge'; StraightEdge.displayName = 'StraightEdge';
StraightEdgeInternal.displayName = 'StraightEdgeInternal';
export default StraightEdge; export { StraightEdge, StraightEdgeInternal };
+9 -5
View File
@@ -1,5 +1,9 @@
export { default as SimpleBezierEdge } from './SimpleBezierEdge'; // We distinguish between internal and exported edges
export { default as SmoothStepEdge } from './SmoothStepEdge'; // The internal edges are used directly like custom edges and always get an id, source and target props
export { default as StepEdge } from './StepEdge'; // If you import an edge from the library, the id is optional and source and target are not used at all
export { default as StraightEdge } from './StraightEdge';
export { default as BezierEdge } from './BezierEdge'; export { SimpleBezierEdge, SimpleBezierEdgeInternal } from './SimpleBezierEdge';
export { SmoothStepEdge, SmoothStepEdgeInternal } from './SmoothStepEdge';
export { StepEdge, StepEdgeInternal } from './StepEdge';
export { StraightEdge, StraightEdgeInternal } from './StraightEdge';
export { BezierEdge, BezierEdgeInternal } from './BezierEdge';
@@ -171,7 +171,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
lib, lib,
}); });
if (isValid) { if (isValid && connection) {
onConnectExtended(connection); onConnectExtended(connection);
} }
@@ -1,6 +1,12 @@
import type { ComponentType } from 'react'; import type { ComponentType } from 'react';
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges'; import {
BezierEdgeInternal,
SmoothStepEdgeInternal,
StepEdgeInternal,
StraightEdgeInternal,
SimpleBezierEdgeInternal,
} from '../../components/Edges';
import wrapEdge from '../../components/Edges/wrapEdge'; import wrapEdge from '../../components/Edges/wrapEdge';
import type { EdgeProps, EdgeTypes, EdgeTypesWrapped } from '../../types'; import type { EdgeProps, EdgeTypes, EdgeTypesWrapped } from '../../types';
@@ -8,18 +14,18 @@ export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypesWrapped;
export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypesWrapped { export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypesWrapped {
const standardTypes: EdgeTypesWrapped = { const standardTypes: EdgeTypesWrapped = {
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeProps>), default: wrapEdge((edgeTypes.default || BezierEdgeInternal) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeProps>), straight: wrapEdge((edgeTypes.bezier || StraightEdgeInternal) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType<EdgeProps>), step: wrapEdge((edgeTypes.step || StepEdgeInternal) as ComponentType<EdgeProps>),
smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType<EdgeProps>), smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdgeInternal) as ComponentType<EdgeProps>),
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdge) as ComponentType<EdgeProps>), simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdgeInternal) as ComponentType<EdgeProps>),
}; };
const wrappedTypes = {} as EdgeTypesWrapped; const wrappedTypes = {} as EdgeTypesWrapped;
const specialTypes: EdgeTypesWrapped = Object.keys(edgeTypes) const specialTypes: EdgeTypesWrapped = Object.keys(edgeTypes)
.filter((k) => !['default', 'bezier'].includes(k)) .filter((k) => !['default', 'bezier'].includes(k))
.reduce((res, key) => { .reduce((res, key) => {
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeProps>); res[key] = wrapEdge((edgeTypes[key] || BezierEdgeInternal) as ComponentType<EdgeProps>);
return res; return res;
}, wrappedTypes); }, wrappedTypes);
@@ -12,7 +12,13 @@ import {
} from '@xyflow/system'; } from '@xyflow/system';
import Attribution from '../../components/Attribution'; import Attribution from '../../components/Attribution';
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges'; import {
BezierEdgeInternal,
SmoothStepEdgeInternal,
StepEdgeInternal,
StraightEdgeInternal,
SimpleBezierEdgeInternal,
} from '../../components/Edges';
import DefaultNode from '../../components/Nodes/DefaultNode'; import DefaultNode from '../../components/Nodes/DefaultNode';
import InputNode from '../../components/Nodes/InputNode'; import InputNode from '../../components/Nodes/InputNode';
import OutputNode from '../../components/Nodes/OutputNode'; import OutputNode from '../../components/Nodes/OutputNode';
@@ -33,11 +39,11 @@ const defaultNodeTypes: NodeTypes = {
}; };
const defaultEdgeTypes: EdgeTypes = { const defaultEdgeTypes: EdgeTypes = {
default: BezierEdge, default: BezierEdgeInternal,
straight: StraightEdge, straight: StraightEdgeInternal,
step: StepEdge, step: StepEdgeInternal,
smoothstep: SmoothStepEdge, smoothstep: SmoothStepEdgeInternal,
simplebezier: SimpleBezierEdge, simplebezier: SimpleBezierEdgeInternal,
}; };
const initNodeOrigin: NodeOrigin = [0, 0]; const initNodeOrigin: NodeOrigin = [0, 0];
@@ -0,0 +1,54 @@
import { useEffect, useMemo, useRef } from 'react';
import { Connection, HandleType, areConnectionMapsEqual, handleConnectionChange } from '@xyflow/system';
import { useStore } from './useStore';
import { useNodeId } from '../contexts/NodeIdContext';
type useHandleConnectionsParams = {
type: HandleType;
id?: string | null;
nodeId?: string;
onConnect?: (connections: Connection[]) => void;
onDisconnect?: (connections: Connection[]) => void;
};
/**
* Hook to check if a <Handle /> is connected to another <Handle /> and get the connections.
*
* @public
* @param param.type - handle type 'source' or 'target'
* @param param.id - the handle id (this is only needed if the node has multiple handles of the same type)
* @param param.nodeId - node id - if not provided, the node id from the NodeIdContext is used
* @param param.onConnect - gets called when a connection is established
* @param param.onDisconnect - gets called when a connection is removed
* @returns an array with connections
*/
export function useHandleConnections({
type,
id = null,
nodeId,
onConnect,
onDisconnect,
}: useHandleConnectionsParams): Connection[] {
const _nodeId = useNodeId();
const prevConnections = useRef<Map<string, Connection> | null>(null);
const currentNodeId = nodeId || _nodeId;
const connections = useStore(
(state) => state.connectionLookup.get(`${currentNodeId}-${type}-${id}`),
areConnectionMapsEqual
);
useEffect(() => {
// @todo dicuss if onConnect/onDisconnect should be called when the component mounts/unmounts
if (prevConnections.current && prevConnections.current !== connections) {
const _connections = connections ?? new Map();
handleConnectionChange(prevConnections.current, _connections, onDisconnect);
handleConnectionChange(_connections, prevConnections.current, onConnect);
}
prevConnections.current = connections ?? new Map();
}, [connections, onConnect, onDisconnect]);
return useMemo(() => Array.from(connections?.values() ?? []), [connections]);
}
+40
View File
@@ -0,0 +1,40 @@
import { useCallback } from 'react';
import { shallow } from 'zustand/shallow';
import { useStore } from '../hooks/useStore';
import type { Node } from '../types';
export function useNodesData<NodeType extends Node = Node>(nodeId: string): NodeType['data'] | null;
export function useNodesData<NodeType extends Node = Node>(nodeIds: string[]): NodeType['data'][];
export function useNodesData<NodeType extends Node = Node>(
nodeIds: string[],
guard: (node: Node) => node is NodeType
): NodeType['data'][];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any {
const nodesData = useStore(
useCallback(
(s) => {
if (!Array.isArray(nodeIds)) {
return s.nodeLookup.get(nodeIds)?.data || null;
}
const data = [];
for (const nodeId of nodeIds) {
const nodeData = s.nodeLookup.get(nodeId)?.data;
if (nodeData) {
data.push(nodeData);
}
}
return data;
},
[nodeIds]
),
shallow
);
return nodesData;
}
+34 -1
View File
@@ -10,7 +10,7 @@ import {
} from '@xyflow/system'; } from '@xyflow/system';
import useViewportHelper from './useViewportHelper'; import useViewportHelper from './useViewportHelper';
import { useStoreApi } from '../hooks/useStore'; import { useStoreApi } from './useStore';
import type { import type {
ReactFlowInstance, ReactFlowInstance,
Instance, Instance,
@@ -24,6 +24,7 @@ import type {
Node, Node,
Edge, Edge,
} from '../types'; } from '../types';
import { isNode } from '../utils';
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlowInstance<NodeData, EdgeData> { export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlowInstance<NodeData, EdgeData> {
@@ -271,6 +272,36 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
return getOutgoersBase(node, nodes, edges); return getOutgoersBase(node, nodes, edges);
}, []); }, []);
const updateNode = useCallback<Instance.UpdateNode>(
(id, nodeUpdate, options = { replace: true }) => {
setNodes((prevNodes) =>
prevNodes.map((node) => {
if (node.id === id) {
const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node as Node) : nodeUpdate;
return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
}
return node;
})
);
},
[setNodes]
);
const updateNodeData = useCallback<Instance.UpdateNodeData>(
(id, dataUpdate, options = { replace: false }) => {
updateNode(
id,
(node) => {
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
},
options
);
},
[updateNode]
);
return useMemo(() => { return useMemo(() => {
return { return {
...viewportHelper, ...viewportHelper,
@@ -289,6 +320,8 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
getConnectedEdges, getConnectedEdges,
getIncomers, getIncomers,
getOutgoers, getOutgoers,
updateNode,
updateNodeData,
}; };
}, [ }, [
viewportHelper, viewportHelper,
+8 -6
View File
@@ -1,11 +1,11 @@
export { default as ReactFlow } from './container/ReactFlow'; export { default as ReactFlow } from './container/ReactFlow';
export { default as Handle } from './components/Handle'; export { default as Handle, type HandleComponentProps } from './components/Handle';
export { default as EdgeText } from './components/Edges/EdgeText'; export { default as EdgeText } from './components/Edges/EdgeText';
export { default as StraightEdge } from './components/Edges/StraightEdge'; export { StraightEdge } from './components/Edges/StraightEdge';
export { default as StepEdge } from './components/Edges/StepEdge'; export { StepEdge } from './components/Edges/StepEdge';
export { default as BezierEdge } from './components/Edges/BezierEdge'; export { BezierEdge } from './components/Edges/BezierEdge';
export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge'; export { SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
export { default as SmoothStepEdge } from './components/Edges/SmoothStepEdge'; export { SmoothStepEdge } from './components/Edges/SmoothStepEdge';
export { default as BaseEdge } from './components/Edges/BaseEdge'; export { default as BaseEdge } from './components/Edges/BaseEdge';
export { default as ReactFlowProvider } from './components/ReactFlowProvider'; export { default as ReactFlowProvider } from './components/ReactFlowProvider';
export { default as Panel, type PanelProps } from './components/Panel'; export { default as Panel, type PanelProps } from './components/Panel';
@@ -22,6 +22,8 @@ export { useStore, useStoreApi } from './hooks/useStore';
export { default as useOnViewportChange, type UseOnViewportChangeOptions } from './hooks/useOnViewportChange'; export { default as useOnViewportChange, type UseOnViewportChangeOptions } from './hooks/useOnViewportChange';
export { default as useOnSelectionChange, type UseOnSelectionChangeOptions } from './hooks/useOnSelectionChange'; export { default as useOnSelectionChange, type UseOnSelectionChangeOptions } from './hooks/useOnSelectionChange';
export { default as useNodesInitialized, type UseNodesInitializedOptions } from './hooks/useNodesInitialized'; export { default as useNodesInitialized, type UseNodesInitializedOptions } from './hooks/useNodesInitialized';
export { useHandleConnections } from './hooks/useHandleConnections';
export { useNodesData } from './hooks/useNodesData';
export { useNodeId } from './contexts/NodeIdContext'; export { useNodeId } from './contexts/NodeIdContext';
export { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes'; export { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes';
+8 -2
View File
@@ -7,6 +7,7 @@ import {
panBy as panBySystem, panBy as panBySystem,
Dimensions, Dimensions,
updateNodeDimensions as updateNodeDimensionsSystem, updateNodeDimensions as updateNodeDimensionsSystem,
updateConnectionLookup,
} from '@xyflow/system'; } from '@xyflow/system';
import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes'; import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -49,8 +50,12 @@ const createRFStore = ({
set({ nodes: nextNodes }); set({ nodes: nextNodes });
}, },
setEdges: (edges: Edge[]) => { setEdges: (edges: Edge[]) => {
const { defaultEdgeOptions = {} } = get(); const { defaultEdgeOptions = {}, connectionLookup } = get();
set({ edges: edges.map((e) => ({ ...defaultEdgeOptions, ...e })) }); const nextEdges = edges.map((e) => ({ ...defaultEdgeOptions, ...e }));
updateConnectionLookup(connectionLookup, nextEdges);
set({ edges: nextEdges });
}, },
// when the user works with an uncontrolled flow, // when the user works with an uncontrolled flow,
// we set a flag `hasDefaultNodes` / `hasDefaultEdges` // we set a flag `hasDefaultNodes` / `hasDefaultEdges`
@@ -326,6 +331,7 @@ const createRFStore = ({
set(currentConnection); set(currentConnection);
}, },
reset: () => { reset: () => {
// @todo: what should we do about this? Do we still need it? // @todo: what should we do about this? Do we still need it?
// if you are on a SPA with multiple flows, we want to make sure that the store gets resetted // if you are on a SPA with multiple flows, we want to make sure that the store gets resetted
+4 -1
View File
@@ -5,6 +5,7 @@ import {
getNodesBounds, getNodesBounds,
getViewportForBounds, getViewportForBounds,
Transform, Transform,
updateConnectionLookup,
} from '@xyflow/system'; } from '@xyflow/system';
import type { Edge, Node, ReactFlowStore } from '../types'; import type { Edge, Node, ReactFlowStore } from '../types';
@@ -22,7 +23,8 @@ const getInitialState = ({
height?: number; height?: number;
fitView?: boolean; fitView?: boolean;
} = {}): ReactFlowStore => { } = {}): ReactFlowStore => {
const nodeLookup = new Map<string, Node>(); const nodeLookup = new Map();
const connectionLookup = updateConnectionLookup(new Map(), edges);
const nextNodes = updateNodes(nodes, nodeLookup, { nodeOrigin: [0, 0], elevateNodesOnSelect: false }); const nextNodes = updateNodes(nodes, nodeLookup, { nodeOrigin: [0, 0], elevateNodesOnSelect: false });
let transform: Transform = [0, 0, 1]; let transform: Transform = [0, 0, 1];
@@ -42,6 +44,7 @@ const getInitialState = ({
nodes: nextNodes, nodes: nextNodes,
nodeLookup, nodeLookup,
edges: edges, edges: edges,
connectionLookup,
onNodesChange: null, onNodesChange: null,
onEdgesChange: null, onEdgesChange: null,
hasDefaultNodes: false, hasDefaultNodes: false,
+20 -3
View File
@@ -13,6 +13,8 @@ import type {
HandleElement, HandleElement,
ConnectionStatus, ConnectionStatus,
EdgePosition, EdgePosition,
Optional,
StepPathOptions,
} from '@xyflow/system'; } from '@xyflow/system';
import { Node } from '.'; import { Node } from '.';
@@ -46,7 +48,12 @@ type BezierEdgeType<T> = DefaultEdge<T> & {
pathOptions?: BezierPathOptions; pathOptions?: BezierPathOptions;
}; };
export type Edge<T = any> = DefaultEdge<T> | SmoothStepEdgeType<T> | BezierEdgeType<T>; type StepEdgeType<T> = DefaultEdge<T> & {
type: 'step';
pathOptions?: StepPathOptions;
};
export type Edge<T = any> = DefaultEdge<T> | SmoothStepEdgeType<T> | BezierEdgeType<T> | StepEdgeType<T>;
export type EdgeMouseHandler = (event: ReactMouseEvent, edge: Edge) => void; export type EdgeMouseHandler = (event: ReactMouseEvent, edge: Edge) => void;
@@ -100,14 +107,24 @@ export type BaseEdgeProps = Pick<EdgeProps, 'style' | 'markerStart' | 'markerEnd
path: string; path: string;
}; };
export type SmoothStepEdgeProps<T = any> = EdgeProps<T> & { export type EdgeComponentProps<T = any> = Optional<Omit<EdgeProps<T>, 'source' | 'target'>, 'id'>;
export type StraightEdgeProps<T = any> = Omit<EdgeComponentProps<T>, 'sourcePosition' | 'targetPosition'>;
export type SmoothStepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: SmoothStepPathOptions; pathOptions?: SmoothStepPathOptions;
}; };
export type BezierEdgeProps<T = any> = EdgeProps<T> & { export type BezierEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: BezierPathOptions; pathOptions?: BezierPathOptions;
}; };
export type StepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: StepPathOptions;
};
export type SimpleBezierEdgeProps<T = any> = EdgeComponentProps<T>;
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void; export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void;
export type ConnectionLineComponentProps = { export type ConnectionLineComponentProps = {
+13
View File
@@ -45,6 +45,17 @@ export namespace Instance {
export type getConnectedEdges = (id: string | (Node | { id: Node['id'] })[]) => Edge[]; export type getConnectedEdges = (id: string | (Node | { id: Node['id'] })[]) => Edge[];
export type getIncomers = (node: string | Node | { id: Node['id'] }) => Node[]; export type getIncomers = (node: string | Node | { id: Node['id'] }) => Node[];
export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[]; export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[];
export type UpdateNode = (
id: string,
dataUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
options?: { replace: boolean }
) => void;
export type UpdateNodeData = (
id: string,
dataUpdate: object | ((node: Node) => object),
options?: { replace: boolean }
) => void;
} }
export type ReactFlowInstance<NodeData = any, EdgeData = any> = { export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
@@ -60,5 +71,7 @@ export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
deleteElements: Instance.DeleteElements; deleteElements: Instance.DeleteElements;
getIntersectingNodes: Instance.GetIntersectingNodes<NodeData>; getIntersectingNodes: Instance.GetIntersectingNodes<NodeData>;
isNodeIntersecting: Instance.IsNodeIntersecting<NodeData>; isNodeIntersecting: Instance.IsNodeIntersecting<NodeData>;
updateNode: Instance.UpdateNode;
updateNodeData: Instance.UpdateNodeData;
viewportInitialized: boolean; viewportInitialized: boolean;
} & Omit<ViewportHelperFunctions, 'initialized'>; } & Omit<ViewportHelperFunctions, 'initialized'>;
+3
View File
@@ -24,6 +24,7 @@ import {
type OnMoveEnd, type OnMoveEnd,
type IsValidConnection, type IsValidConnection,
type UpdateConnection, type UpdateConnection,
Connection,
} from '@xyflow/system'; } from '@xyflow/system';
import type { import type {
@@ -49,6 +50,8 @@ export type ReactFlowStore = {
nodes: Node[]; nodes: Node[];
nodeLookup: Map<string, Node>; nodeLookup: Map<string, Node>;
edges: Edge[]; edges: Edge[];
connectionLookup: Map<string, Map<string, Connection>>;
onNodesChange: OnNodesChange | null; onNodesChange: OnNodesChange | null;
onEdgesChange: OnEdgesChange | null; onEdgesChange: OnEdgesChange | null;
hasDefaultNodes: boolean; hasDefaultNodes: boolean;
+2 -2
View File
@@ -10,8 +10,8 @@ import {
import type { Edge, Node } from '../types'; import type { Edge, Node } from '../types';
export const isNode = isNodeBase<Node, Edge>; export const isNode = isNodeBase<Node>;
export const isEdge = isEdgeBase<Node, Edge>; export const isEdge = isEdgeBase<Edge>;
export const getOutgoers = getOutgoersBase<Node, Edge>; export const getOutgoers = getOutgoersBase<Node, Edge>;
export const getIncomers = getIncomersBase<Node, Edge>; export const getIncomers = getIncomersBase<Node, Edge>;
export const addEdge = addEdgeBase<Edge>; export const addEdge = addEdgeBase<Edge>;
+34 -9
View File
@@ -1,3 +1,28 @@
## 0.0.29
Another huge update for Svelte Flow 🙏 Handling data flows will be way easier with the new hooks and functions. You can now subscribe to connected nodes, receive data and update nodes more easily. We fix a big issue about the `<Handle />` component. No more `on:connect` that only worked for target `<Handle />` components but `onconnect` and `ondisconnect` that works for every `<Handle />`.
### Features
- add `useHandleConnections` hook for receiving connected node and handle ids for a specific handle
- add `useNodesData(ids: string | string[])` hook for receiving data from other nodes
- export `updateNode` and `updateNodeData` from `useSvelteFlow` to update a node or the data object
- add `onedgecreate` function for passing a certain id or other attributes to a newly created edge
### ⚠️ Breaking
- replace `on:connect`, `on:connectstart` and `on:connectend` with `onconnect`, `onconnectstart` and `onconnectend`, no need to forward `on:connect..` anymore
### Fixes and minor changes
- `onconnect` and `ondisconnect` callback work for `<Handle />` component
- don't delete a node when user presses Backspace inside an input/textarea/.nokey element
- `bgColor` prop for Background didn't work
- prefix css vars with "xy-"
- don't update nodes and edges on pane click if not necessary
- cleaner types for exported edges
- fix `getIntersectingNodes` bug when passing `Rect`
## 0.0.28 ## 0.0.28
This is a huge update! We added a new `<NodeToolbar />` component and a new `colorMode` ('light' | 'dark' | 'system') prop for toggling dark/light mode. This is a huge update! We added a new `<NodeToolbar />` component and a new `colorMode` ('light' | 'dark' | 'system') prop for toggling dark/light mode.
@@ -7,7 +32,7 @@ There are also some breaking changes again (sorry!) but we are very close to the
- add `<NodeToolbar />` component - add `<NodeToolbar />` component
- add `on:selectionclick` and `on:selectioncontextmenu` event handlers - add `on:selectionclick` and `on:selectioncontextmenu` event handlers
- add `ondelete({ nodes, edges })` handler - add `ondelete({ nodes, edges })` handler
- add `zoomActivationKey` prop - add `zoomActivationKey` prop
- add `width` and `height` prop to custom `NodeProps` type - add `width` and `height` prop to custom `NodeProps` type
- add `colorMode` prop ('light' | 'dark' | 'system') - add `colorMode` prop ('light' | 'dark' | 'system')
- ⚠️ replace `xPos` and `yPos` with `positionAbsolute` prop to custom `NodeProps` type - ⚠️ replace `xPos` and `yPos` with `positionAbsolute` prop to custom `NodeProps` type
@@ -18,7 +43,7 @@ There are also some breaking changes again (sorry!) but we are very close to the
## 0.0.27 ## 0.0.27
- add `selectionOnDrag` prop - can be used to create figma-like controls in combination with `panOnDrag={false}` / `panOnDrag={[1, 2]}` + `panOnScroll={true}` - add `selectionOnDrag` prop - can be used to create figma-like controls in combination with `panOnDrag={false}` / `panOnDrag={[1, 2]}` + `panOnScroll={true}`
- ⚠️ rename `screenToFlowCoordinate` to `screenToFlowPosition` - ⚠️ rename `screenToFlowCoordinate` to `screenToFlowPosition`
- ⚠️ rename `flowToScreenCoordinate` to `flowToScreenPosition` - ⚠️ rename `flowToScreenCoordinate` to `flowToScreenPosition`
- ⚠️ rename `getTransformForBounds` to `getViewportForBounds` (return `{ x: number, y: number, zoom: number }` instead of `[number, number, number]`) - ⚠️ rename `getTransformForBounds` to `getViewportForBounds` (return `{ x: number, y: number, zoom: number }` instead of `[number, number, number]`)
@@ -67,7 +92,7 @@ There are also some breaking changes again (sorry!) but we are very close to the
## 0.0.22 ## 0.0.22
- add `connectionLine` slot for rendering a custom connection line - add `connectionLine` slot for rendering a custom connection line
- add `connectionLineStyle` and `connectionLineContainerStyle` props - add `connectionLineStyle` and `connectionLineContainerStyle` props
- add `useConnection` hook - add `useConnection` hook
- add `nodeDragThreshold` prop - add `nodeDragThreshold` prop
@@ -100,7 +125,7 @@ There are also some breaking changes again (sorry!) but we are very close to the
## 0.0.18 ## 0.0.18
- add `nodesDraggable` prop - add `nodesDraggable` prop
- minimap: add default background - minimap: add default background
## 0.0.17 ## 0.0.17
@@ -113,7 +138,7 @@ There are also some breaking changes again (sorry!) but we are very close to the
## 0.0.15 ## 0.0.15
- fix wrongly displayed connectionline - fix wrongly displayed connectionline
## 0.0.14 ## 0.0.14
@@ -152,14 +177,14 @@ this version is broken because of a wrong path in the package.json
- add `connectionRadius` - add `connectionRadius`
## 0.0.1 ## 0.0.1
Svelte Flow alpha is here 🔥 You can expect some changes until we reach 1.0.0 but we try to stick as close as possible to the React Flow API. There are no docs yet, but we are working on it! For now the easiest way is to use the autocomplete of your IDE, lookup the props in the SvelteFlow component or check out the React Flow docs. Svelte Flow alpha is here 🔥 You can expect some changes until we reach 1.0.0 but we try to stick as close as possible to the React Flow API. There are no docs yet, but we are working on it! For now the easiest way is to use the autocomplete of your IDE, lookup the props in the SvelteFlow component or check out the React Flow docs.
This very first release comes with lots of features already: This very first release comes with lots of features already:
- pass `nodes` and `edges` as writables - pass `nodes` and `edges` as writables
- draggable, selectable and deletable nodes - draggable, selectable and deletable nodes
- support for custom `nodeTypes` and `edgeTypes` - support for custom `nodeTypes` and `edgeTypes`
- basic viewport settings like `fitView`, `minZoom` and `maxZoom` - basic viewport settings like `fitView`, `minZoom` and `maxZoom`
- additional components: `<MiniMap />`, `<Controls />` & `<Background />` - additional components: `<MiniMap />`, `<Controls />` & `<Background />`
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/svelte", "name": "@xyflow/svelte",
"version": "0.0.28", "version": "0.0.29",
"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",
@@ -41,7 +41,7 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@svelte-put/shortcut": "^3.0.0", "@svelte-put/shortcut": "^3.1.0",
"@xyflow/system": "workspace:*", "@xyflow/system": "workspace:*",
"classcat": "^5.0.4" "classcat": "^5.0.4"
}, },
@@ -6,7 +6,7 @@
import { errorMessages, getMarkerId } from '@xyflow/system'; import { errorMessages, getMarkerId } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import BezierEdge from '$lib/components/edges/BezierEdge.svelte'; import { BezierEdgeInternal } from '$lib/components/edges';
import type { EdgeLayouted, Edge } from '$lib/types'; import type { EdgeLayouted, Edge } from '$lib/types';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
@@ -57,7 +57,7 @@
edgecontextmenu: { edge: Edge; event: MouseEvent }; edgecontextmenu: { edge: Edge; event: MouseEvent };
}>(); }>();
$: edgeComponent = $edgeTypes[type!] || BezierEdge; $: edgeComponent = $edgeTypes[type!] || BezierEdgeInternal;
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined; $: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined; $: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
@@ -1,17 +1,18 @@
<script lang="ts"> <script lang="ts">
import { getContext, createEventDispatcher } from 'svelte'; import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import cc from 'classcat'; import cc from 'classcat';
import { import {
Position, Position,
XYHandle, XYHandle,
isMouseEvent, isMouseEvent,
type Connection, type Connection,
type HandleType areConnectionMapsEqual,
handleConnectionChange
} from '@xyflow/system'; } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { HandleComponentProps } from '$lib/types'; import type { HandleComponentProps } from '$lib/types';
import type { Writable } from 'svelte/store';
type $$Props = HandleComponentProps; type $$Props = HandleComponentProps;
@@ -20,6 +21,8 @@
export let position: $$Props['position'] = Position.Top; export let position: $$Props['position'] = Position.Top;
export let style: $$Props['style'] = undefined; export let style: $$Props['style'] = undefined;
export let isConnectable: $$Props['isConnectable'] = undefined; export let isConnectable: $$Props['isConnectable'] = undefined;
export let onconnect: $$Props['onconnect'] = undefined;
export let ondisconnect: $$Props['ondisconnect'] = undefined;
// export let isConnectableStart: $$Props['isConnectableStart'] = undefined; // export let isConnectableStart: $$Props['isConnectableStart'] = undefined;
// export let isConnectableEnd: $$Props['isConnectableEnd'] = undefined; // export let isConnectableEnd: $$Props['isConnectableEnd'] = undefined;
@@ -32,18 +35,6 @@
$: handleConnectable = isConnectable !== undefined ? isConnectable : $connectable; $: handleConnectable = isConnectable !== undefined ? isConnectable : $connectable;
const handleId = id || null; const handleId = id || null;
const dispatch = createEventDispatcher<{
connect: { connection: Connection };
connectstart: {
event: MouseEvent | TouchEvent;
nodeId: string | null;
handleId: string | null;
handleType: HandleType | null;
};
connectend: {
event: MouseEvent | TouchEvent;
};
}>();
const store = useStore(); const store = useStore();
const { const {
@@ -55,10 +46,16 @@
isValidConnection, isValidConnection,
lib, lib,
addEdge, addEdge,
onedgecreate,
panBy, panBy,
cancelConnection, cancelConnection,
updateConnection, updateConnection,
autoPanOnConnect autoPanOnConnect,
edges,
connectionLookup,
onconnect: onConnectAction,
onconnectstart: onConnectStartAction,
onconnectend: onConnectEndAction
} = store; } = store;
function onPointerDown(event: MouseEvent | TouchEvent) { function onPointerDown(event: MouseEvent | TouchEvent) {
@@ -80,28 +77,50 @@
cancelConnection, cancelConnection,
panBy, panBy,
onConnect: (connection) => { onConnect: (connection) => {
addEdge(connection); const edge = $onedgecreate ? $onedgecreate(connection) : connection;
// @todo: should we change/ improve the stuff we are passing here? if (!edge) {
// instead of source/target we could pass fromNodeId, fromHandleId, etc return;
dispatch('connect', { connection }); }
addEdge(edge);
$onConnectAction?.(connection);
}, },
onConnectStart: (event, startParams) => { onConnectStart: (event, startParams) => {
dispatch('connectstart', { $onConnectStartAction?.(event, {
event,
nodeId: startParams.nodeId, nodeId: startParams.nodeId,
handleId: startParams.handleId, handleId: startParams.handleId,
handleType: startParams.handleType handleType: startParams.handleType
}); });
}, },
onConnectEnd: (event) => { onConnectEnd: (event) => {
dispatch('connectend', { event }); $onConnectEndAction?.(event);
}, },
getTransform: () => [$viewport.x, $viewport.y, $viewport.zoom] getTransform: () => [$viewport.x, $viewport.y, $viewport.zoom]
}); });
} }
} }
let prevConnections: Map<string, Connection> | null = null;
let connections: Map<string, Connection> | undefined;
$: if (onconnect || ondisconnect) {
// connectionLookup is not reactive, so we use edges to get notified about updates
$edges;
connections = $connectionLookup.get(`${nodeId}-${type}-${id || null}`);
}
$: {
if (prevConnections && !areConnectionMapsEqual(connections, prevConnections)) {
const _connections = connections ?? new Map();
handleConnectionChange(prevConnections, _connections, ondisconnect);
handleConnectionChange(_connections, prevConnections, onconnect);
}
prevConnections = connections ?? new Map();
}
// @todo implement connectablestart, connectableend // @todo implement connectablestart, connectableend
</script> </script>
@@ -1,10 +1,10 @@
<script lang="ts"> <script lang="ts">
import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut'; import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut';
import { isInputDOMNode, isMacOs } from '@xyflow/system';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { KeyHandlerProps } from './types'; import type { KeyHandlerProps } from './types';
import type { KeyDefinition, KeyDefinitionObject } from '$lib/types'; import type { KeyDefinition, KeyDefinitionObject } from '$lib/types';
import { isMacOs } from '@xyflow/system';
type $$Props = KeyHandlerProps; type $$Props = KeyHandlerProps;
@@ -23,7 +23,7 @@
} = useStore(); } = useStore();
function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject { function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject {
return typeof key === 'object'; return key !== null && typeof key === 'object';
} }
function getModifier(key?: KeyDefinition | null): ShortcutModifierDefinition { function getModifier(key?: KeyDefinition | null): ShortcutModifierDefinition {
@@ -71,16 +71,19 @@
trigger: [ trigger: [
{ {
...selectionKeyDefinition, ...selectionKeyDefinition,
callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(true) enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
}} }}
use:shortcut={{ use:shortcut={{
trigger: [ trigger: [
{ {
...selectionKeyDefinition, ...selectionKeyDefinition,
callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(false) enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -89,7 +92,8 @@
trigger: [ trigger: [
{ {
...multiSelectionKeyDefinition, ...multiSelectionKeyDefinition,
callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(true) enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -98,7 +102,8 @@
trigger: [ trigger: [
{ {
...multiSelectionKeyDefinition, ...multiSelectionKeyDefinition,
callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(false) enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -107,7 +112,8 @@
trigger: [ trigger: [
{ {
...deleteKeyDefinition, ...deleteKeyDefinition,
callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(true) enabled: deleteKeyDefinition.key !== null,
callback: (detail) => !isInputDOMNode(detail.originalEvent) && deleteKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -116,7 +122,8 @@
trigger: [ trigger: [
{ {
...deleteKeyDefinition, ...deleteKeyDefinition,
callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(false) enabled: deleteKeyDefinition.key !== null,
callback: () => deleteKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -125,7 +132,8 @@
trigger: [ trigger: [
{ {
...panActivationKeyDefinition, ...panActivationKeyDefinition,
callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(true) enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -134,7 +142,8 @@
trigger: [ trigger: [
{ {
...panActivationKeyDefinition, ...panActivationKeyDefinition,
callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(false) enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -143,7 +152,8 @@
trigger: [ trigger: [
{ {
...zoomActivationKeyDefinition, ...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(true) enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(true)
} }
], ],
type: 'keydown' type: 'keydown'
@@ -152,7 +162,8 @@
trigger: [ trigger: [
{ {
...zoomActivationKeyDefinition, ...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(false) enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(false)
} }
], ],
type: 'keyup' type: 'keyup'
@@ -194,9 +194,6 @@
positionAbsolute={{ x: positionX, y: positionY }} positionAbsolute={{ x: positionX, y: positionY }}
{width} {width}
{height} {height}
on:connectstart
on:connect
on:connectend
/> />
</div> </div>
{/if} {/if}
@@ -1,30 +1,48 @@
<script lang="ts"> <script lang="ts">
import { getBezierPath } from '@xyflow/system'; import { getBezierPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types'; import type { BezierEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; type $$Props = BezierEdgeProps;
export let id: $$Props['id'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let pathOptions: $$Props['pathOptions'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getBezierPath({ $: [path, labelX, labelY] = getBezierPath({
sourceX: $$props.sourceX, sourceX,
sourceY: $$props.sourceY, sourceY,
targetX: $$props.targetX, targetX,
targetY: $$props.targetY, targetY,
sourcePosition: $$props.sourcePosition, sourcePosition,
targetPosition: $$props.targetPosition targetPosition,
curvature: pathOptions?.curvature
}); });
</script> </script>
<BaseEdge <BaseEdge
{id}
{path} {path}
{labelX} {labelX}
{labelY} {labelY}
id={$$props.id} {label}
label={$$props.label} {labelStyle}
labelStyle={$$props.labelStyle} {markerStart}
markerStart={$$props.markerStart} {markerEnd}
markerEnd={$$props.markerEnd} {interactionWidth}
interactionWidth={$$props.interactionWidth} {style}
style={$$props.style}
/> />
@@ -0,0 +1,63 @@
<script lang="ts">
import { getBezierPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition
});
// hopefully with Svelte5, we don't need this kind of workaround anymore
id;
source;
target;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script>
<BaseEdge
{path}
{labelX}
{labelY}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{style}
/>
@@ -1,30 +1,49 @@
<script lang="ts"> <script lang="ts">
import { getSmoothStepPath } from '@xyflow/system'; import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types'; import type { SmoothStepEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; type $$Props = SmoothStepEdgeProps;
export let id: $$Props['id'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let pathOptions: $$Props['pathOptions'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({ $: [path, labelX, labelY] = getSmoothStepPath({
sourceX: $$props.sourceX, sourceX,
sourceY: $$props.sourceY, sourceY,
targetX: $$props.targetX, targetX,
targetY: $$props.targetY, targetY,
sourcePosition: $$props.sourcePosition, sourcePosition,
targetPosition: $$props.targetPosition targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset
}); });
</script> </script>
<BaseEdge <BaseEdge
{id}
{path} {path}
{labelX} {labelX}
{labelY} {labelY}
id={$$props.id} {label}
label={$$props.label} {labelStyle}
labelStyle={$$props.labelStyle} {markerStart}
markerStart={$$props.markerStart} {markerEnd}
markerEnd={$$props.markerEnd} {interactionWidth}
interactionWidth={$$props.interactionWidth} {style}
style={$$props.style}
/> />
@@ -0,0 +1,63 @@
<script lang="ts">
import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition
});
id;
source;
target;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script>
<BaseEdge
{path}
{labelX}
{labelY}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{style}
/>
@@ -1,31 +1,49 @@
<script lang="ts"> <script lang="ts">
import { getSmoothStepPath } from '@xyflow/system'; import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types'; import type { StepEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; type $$Props = StepEdgeProps;
export let id: $$Props['id'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let pathOptions: $$Props['pathOptions'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
$: [path, labelX, labelY] = getSmoothStepPath({ $: [path, labelX, labelY] = getSmoothStepPath({
sourceX: $$props.sourceX, sourceX,
sourceY: $$props.sourceY, sourceY,
targetX: $$props.targetX, targetX,
targetY: $$props.targetY, targetY,
sourcePosition: $$props.sourcePosition, sourcePosition,
targetPosition: $$props.targetPosition, targetPosition,
borderRadius: 0 borderRadius: 0,
offset: pathOptions?.offset
}); });
</script> </script>
<BaseEdge <BaseEdge
{id}
{path} {path}
{labelX} {labelX}
{labelY} {labelY}
id={$$props.id} {label}
label={$$props.label} {labelStyle}
labelStyle={$$props.labelStyle} {markerStart}
markerStart={$$props.markerStart} {markerEnd}
markerEnd={$$props.markerEnd} {interactionWidth}
interactionWidth={$$props.interactionWidth} {style}
style={$$props.style}
/> />
@@ -0,0 +1,64 @@
<script lang="ts">
import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let data: $$Props['data'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: 0
});
id;
source;
target;
animated;
selected;
data;
sourceHandleId;
targetHandleId;
</script>
<BaseEdge
{path}
{labelX}
{labelY}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{style}
/>
@@ -1,28 +1,42 @@
<script lang="ts"> <script lang="ts">
import { getStraightPath } from '@xyflow/system'; import { getStraightPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types'; import type { StraightEdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge'; import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps; type $$Props = StraightEdgeProps;
export let id: $$Props['id'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
$: [path, labelX, labelY] = getStraightPath({ $: [path, labelX, labelY] = getStraightPath({
sourceX: $$props.sourceX, sourceX,
sourceY: $$props.sourceY, sourceY,
targetX: $$props.targetX, targetX,
targetY: $$props.targetY targetY
}); });
</script> </script>
<BaseEdge <BaseEdge
{id}
{path} {path}
{labelX} {labelX}
{labelY} {labelY}
id={$$props.id} {label}
label={$$props.label} {labelStyle}
labelStyle={$$props.labelStyle} {markerStart}
markerStart={$$props.markerStart} {markerEnd}
markerEnd={$$props.markerEnd} {interactionWidth}
interactionWidth={$$props.interactionWidth} {style}
style={$$props.style}
/> />
@@ -0,0 +1,63 @@
<script lang="ts">
import { getStraightPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import { BaseEdge } from '$lib/components/BaseEdge';
type $$Props = EdgeProps;
// these props are not used in this edge, but passed to every custom edge component
export let id: $$Props['id'] = '';
export let source: $$Props['source'] = '';
export let target: $$Props['target'] = '';
export let animated: $$Props['animated'] = undefined;
export let selected: $$Props['selected'] = undefined;
export let label: $$Props['label'] = undefined;
export let labelStyle: $$Props['labelStyle'] = undefined;
export let data: $$Props['data'] = undefined;
export let style: $$Props['style'] = undefined;
export let markerStart: $$Props['markerStart'] = undefined;
export let markerEnd: $$Props['markerEnd'] = undefined;
export let interactionWidth: $$Props['interactionWidth'] = undefined;
export let sourceX: $$Props['sourceX'];
export let sourceY: $$Props['sourceY'];
export let sourcePosition: $$Props['sourcePosition'];
export let sourceHandleId: $$Props['sourceHandleId'] = undefined;
export let targetX: $$Props['targetX'];
export let targetY: $$Props['targetY'];
export let targetPosition: $$Props['targetPosition'];
export let targetHandleId: $$Props['targetHandleId'] = undefined;
$: [path, labelX, labelY] = getStraightPath({
sourceX,
sourceY,
targetX,
targetY
});
id;
source;
target;
animated;
selected;
data;
sourcePosition;
targetPosition;
sourceHandleId;
targetHandleId;
</script>
<BaseEdge
{path}
{labelX}
{labelY}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{style}
/>
@@ -1,4 +1,17 @@
// We distinguish between internal and exported edges
// The internal edges are used directly like custom edges and always get an id, source and target props
// If you import an edge from the library, the id is optional and source and target are not used at all
// @todo: how can we prevent this duplication in ...Edge/ ...EdgeInternal?
// both are quite similar, it's just about 1-2 props that are different
export { default as BezierEdge } from './BezierEdge.svelte'; export { default as BezierEdge } from './BezierEdge.svelte';
export { default as StraightEdge } from './StraightEdge.svelte'; export { default as BezierEdgeInternal } from './BezierEdgeInternal.svelte';
export { default as SmoothStepEdge } from './SmoothStepEdge.svelte'; export { default as SmoothStepEdge } from './SmoothStepEdge.svelte';
export { default as SmoothStepEdgeInternal } from './SmoothStepEdgeInternal.svelte';
export { default as StraightEdge } from './StraightEdge.svelte';
export { default as StraightEdgeInternal } from './StraightEdgeInternal.svelte';
export { default as StepEdge } from './StepEdge.svelte'; export { default as StepEdge } from './StepEdge.svelte';
export { default as StepEdgeInternal } from './StepEdgeInternal.svelte';
@@ -37,6 +37,6 @@
isConnectable; isConnectable;
</script> </script>
<Handle type="target" position={targetPosition} on:connectstart on:connect on:connectend /> <Handle type="target" position={targetPosition} />
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition} on:connectstart on:connect on:connectend /> <Handle type="source" position={sourcePosition} />
@@ -39,4 +39,4 @@
</script> </script>
{data?.label} {data?.label}
<Handle type="source" position={sourcePosition} on:connectstart on:connect on:connectend /> <Handle type="source" position={sourcePosition} />
@@ -36,4 +36,4 @@
</script> </script>
{data?.label} {data?.label}
<Handle type="target" position={targetPosition} on:connectstart on:connect on:connectend /> <Handle type="target" position={targetPosition} />
@@ -83,9 +83,6 @@
on:nodemouseenter on:nodemouseenter
on:nodemousemove on:nodemousemove
on:nodemouseleave on:nodemouseleave
on:connectstart
on:connect
on:connectend
on:nodedrag on:nodedrag
on:nodedragstart on:nodedragstart
on:nodedragstop on:nodedragstop
@@ -71,12 +71,16 @@
export let autoPanOnNodeDrag: $$Props['autoPanOnNodeDrag'] = true; export let autoPanOnNodeDrag: $$Props['autoPanOnNodeDrag'] = true;
export let onerror: $$Props['onerror'] = undefined; export let onerror: $$Props['onerror'] = undefined;
export let ondelete: $$Props['ondelete'] = undefined; export let ondelete: $$Props['ondelete'] = undefined;
export let onedgecreate: $$Props['onedgecreate'] = undefined;
export let attributionPosition: $$Props['attributionPosition'] = undefined; export let attributionPosition: $$Props['attributionPosition'] = undefined;
export let proOptions: $$Props['proOptions'] = undefined; export let proOptions: $$Props['proOptions'] = undefined;
export let defaultEdgeOptions: $$Props['defaultEdgeOptions'] = undefined; export let defaultEdgeOptions: $$Props['defaultEdgeOptions'] = undefined;
export let width: $$Props['width'] = undefined; export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined; export let height: $$Props['height'] = undefined;
export let colorMode: $$Props['colorMode'] = 'light'; export let colorMode: $$Props['colorMode'] = 'light';
export let onconnect: $$Props['onconnect'] = undefined;
export let onconnectstart: $$Props['onconnectstart'] = undefined;
export let onconnectend: $$Props['onconnectend'] = undefined;
export let defaultMarkerColor = '#b1b1b7'; export let defaultMarkerColor = '#b1b1b7';
@@ -149,8 +153,12 @@
autoPanOnNodeDrag, autoPanOnNodeDrag,
onerror, onerror,
ondelete, ondelete,
onedgecreate,
connectionMode, connectionMode,
nodeDragThreshold nodeDragThreshold,
onconnect,
onconnectstart,
onconnectend
}; };
updateStoreByKeys(store, updatableProps); updateStoreByKeys(store, updatableProps);
@@ -215,9 +223,6 @@
on:nodemouseenter on:nodemouseenter
on:nodemousemove on:nodemousemove
on:nodemouseleave on:nodemouseleave
on:connectstart
on:connect
on:connectend
on:nodedragstart on:nodedragstart
on:nodedrag on:nodedrag
on:nodedragstop on:nodedragstop
@@ -15,7 +15,10 @@ import type {
ConnectionMode, ConnectionMode,
PanelPosition, PanelPosition,
ProOptions, ProOptions,
ColorMode ColorMode,
OnConnect,
OnConnectStart,
OnConnectEnd
} from '@xyflow/system'; } from '@xyflow/system';
import type { import type {
@@ -26,7 +29,8 @@ import type {
EdgeTypes, EdgeTypes,
DefaultEdgeOptions, DefaultEdgeOptions,
FitViewOptions, FitViewOptions,
OnDelete OnDelete,
OnEdgeCreate
} from '$lib/types'; } from '$lib/types';
import type { Writable } from 'svelte/store'; import type { Writable } from 'svelte/store';
@@ -89,4 +93,10 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
onMoveEnd?: OnMoveEnd; onMoveEnd?: OnMoveEnd;
onerror?: OnError; onerror?: OnError;
ondelete?: OnDelete; ondelete?: OnDelete;
onedgecreate?: OnEdgeCreate;
onconnect?: OnConnect;
onconnectstart?: OnConnectStart;
onconnectend?: OnConnectEnd;
}; };
@@ -64,7 +64,11 @@ export type UpdatableStoreProps = {
connectionMode?: UnwrapWritable<SvelteFlowStore['connectionMode']>; connectionMode?: UnwrapWritable<SvelteFlowStore['connectionMode']>;
onerror?: UnwrapWritable<SvelteFlowStore['onerror']>; onerror?: UnwrapWritable<SvelteFlowStore['onerror']>;
ondelete?: UnwrapWritable<SvelteFlowStore['ondelete']>; ondelete?: UnwrapWritable<SvelteFlowStore['ondelete']>;
onedgecreate?: UnwrapWritable<SvelteFlowStore['onedgecreate']>;
nodeDragThreshold?: UnwrapWritable<SvelteFlowStore['nodeDragThreshold']>; nodeDragThreshold?: UnwrapWritable<SvelteFlowStore['nodeDragThreshold']>;
onconnect?: UnwrapWritable<SvelteFlowStore['onconnect']>;
onconnectstart?: UnwrapWritable<SvelteFlowStore['onconnectstart']>;
onconnectend?: UnwrapWritable<SvelteFlowStore['onconnectend']>;
}; };
export function updateStoreByKeys(store: SvelteFlowStore, keys: UpdatableStoreProps) { export function updateStoreByKeys(store: SvelteFlowStore, keys: UpdatableStoreProps) {
@@ -0,0 +1,30 @@
import { derived } from 'svelte/store';
import { areConnectionMapsEqual, type Connection, type HandleType } from '@xyflow/system';
import { useStore } from '$lib/store';
export type useHandleConnectionsParams = {
nodeId: string;
type: HandleType;
id?: string | null;
};
const initialConnections: Connection[] = [];
export function useHandleConnections({ nodeId, type, id = null }: useHandleConnectionsParams) {
const { edges, connectionLookup } = useStore();
let prevConnections: Map<string, Connection> | undefined = undefined;
return derived(
[edges, connectionLookup],
([, connectionLookup], set) => {
const nextConnections = connectionLookup.get(`${nodeId}-${type}-${id || null}`);
if (!areConnectionMapsEqual(nextConnections, prevConnections)) {
prevConnections = nextConnections;
set(Array.from(prevConnections?.values() || []));
}
},
initialConnections
);
}
@@ -0,0 +1,64 @@
import { derived, type Readable } from 'svelte/store';
import type { Node } from '$lib/types';
import { useStore } from '$lib/store';
function areNodesDataEqual(a: Node['data'][] | null, b: Node['data'][] | null) {
if ((!a && !b) || (!a?.length && !b?.length)) {
true;
}
if (!a || !b || a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
export function useNodesData<NodeType extends Node = Node>(
nodeId: string
): Readable<NodeType['data'] | null>;
export function useNodesData<NodeType extends Node = Node>(
nodeIds: string[]
): Readable<NodeType['data'][]>;
export function useNodesData<NodeType extends Node = Node>(
nodeIds: string[],
guard: (node: Node) => node is NodeType
): Readable<NodeType['data'][]>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any {
const { nodes, nodeLookup } = useStore();
let prevNodesData: (Node['data'] | null)[] | null = null;
return derived([nodes, nodeLookup], ([, nodeLookup], set) => {
let nextNodesData: (Node['data'] | null)[] | null = null;
const nodeIdArray = Array.isArray(nodeIds);
if (!nodeIdArray) {
nextNodesData = [nodeLookup.get(nodeIds)?.data || null];
} else {
const data = [];
for (const nodeId of nodeIds) {
const nodeData = nodeLookup.get(nodeId)?.data;
if (nodeData) {
data.push(nodeData);
}
}
nextNodesData = data;
}
if (!areNodesDataEqual(nextNodesData, prevNodesData)) {
prevNodesData = nextNodesData;
set(nodeIdArray ? nextNodesData : nextNodesData[0]);
}
});
}
+41 -30
View File
@@ -1,7 +1,5 @@
import { get, type Writable } from 'svelte/store'; import { get, type Writable } from 'svelte/store';
import { import {
getIncomersBase,
getOutgoersBase,
getOverlappingArea, getOverlappingArea,
isRectObject, isRectObject,
nodeToRect, nodeToRect,
@@ -20,6 +18,7 @@ import {
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { Edge, FitViewOptions, Node } from '$lib/types'; import type { Edge, FitViewOptions, Node } from '$lib/types';
import { isNode } from '$lib/utils';
export function useSvelteFlow(): { export function useSvelteFlow(): {
zoomIn: ZoomInOut; zoomIn: ZoomInOut;
@@ -48,9 +47,16 @@ export function useSvelteFlow(): {
screenToFlowPosition: (position: XYPosition) => XYPosition; screenToFlowPosition: (position: XYPosition) => XYPosition;
flowToScreenPosition: (position: XYPosition) => XYPosition; flowToScreenPosition: (position: XYPosition) => XYPosition;
viewport: Writable<Viewport>; viewport: Writable<Viewport>;
getConnectedEdges: (id: string | (Node | { id: Node['id'] })[]) => Edge[]; updateNode: (
getIncomers: (node: string | Node | { id: Node['id'] }) => Node[]; id: string,
getOutgoers: (node: string | Node | { id: Node['id'] }) => Node[]; nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
options?: { replace: boolean }
) => void;
updateNodeData: (
id: string,
dataUpdate: object | ((node: Node) => object),
options?: { replace: boolean }
) => void;
toObject: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport }; toObject: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport };
} { } {
const { const {
@@ -84,6 +90,24 @@ export function useSvelteFlow(): {
return [nodeRect, node, isRect]; return [nodeRect, node, isRect];
}; };
const updateNode = (
id: string,
nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
options: { replace: boolean } = { replace: false }
) => {
nodes.update((nds) =>
nds.map((node) => {
if (node.id === id) {
const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node as Node) : nodeUpdate;
return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
}
return node;
})
);
};
return { return {
zoomIn, zoomIn,
zoomOut, zoomOut,
@@ -136,12 +160,12 @@ export function useSvelteFlow(): {
) => { ) => {
const [nodeRect, node, isRect] = getNodeRect(nodeOrRect); const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
if (!nodeRect || !node) { if (!nodeRect) {
return []; return [];
} }
return (nodesToIntersect || get(nodes)).filter((n) => { return (nodesToIntersect || get(nodes)).filter((n) => {
if (!isRect && (n.id === node.id || !n.computed?.positionAbsolute)) { if (!isRect && (n.id === node!.id || !n.computed?.positionAbsolute)) {
return false; return false;
} }
@@ -232,29 +256,6 @@ export function useSvelteFlow(): {
y: rendererPosition.y + domY y: rendererPosition.y + domY
}; };
}, },
getConnectedEdges: (node) => {
const nodeIds = new Set();
if (typeof node === 'string') {
nodeIds.add(node);
} else if (node.length >= 1) {
node.forEach((n) => {
nodeIds.add(n.id);
});
}
return get(edges).filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
},
getIncomers: (node) => {
const _node = typeof node === 'string' ? { id: node } : node;
return getIncomersBase(_node, get(nodes), get(edges));
},
getOutgoers: (node) => {
const _node = typeof node === 'string' ? { id: node } : node;
return getOutgoersBase(_node, get(nodes), get(edges));
},
toObject: () => { toObject: () => {
return { return {
nodes: get(nodes).map((node) => ({ nodes: get(nodes).map((node) => ({
@@ -268,6 +269,16 @@ export function useSvelteFlow(): {
viewport: { ...get(viewport) } viewport: { ...get(viewport) }
}; };
}, },
updateNode,
updateNodeData: (id, dataUpdate, options) => {
updateNode(id, (node) => {
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
return options?.replace
? { ...node, data: nextData }
: { ...node, data: { ...node.data, ...nextData } };
});
},
viewport viewport
}; };
} }
+13 -2
View File
@@ -7,7 +7,7 @@ export * from '$lib/container/Panel';
export * from '$lib/components/SvelteFlowProvider'; export * from '$lib/components/SvelteFlowProvider';
export * from '$lib/components/EdgeLabelRenderer'; export * from '$lib/components/EdgeLabelRenderer';
export * from '$lib/components/BaseEdge'; export * from '$lib/components/BaseEdge';
export * from '$lib/components/edges'; export { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '$lib/components/edges';
export * from '$lib/components/Handle'; export * from '$lib/components/Handle';
// plugins // plugins
@@ -27,9 +27,20 @@ export * from '$lib/hooks/useSvelteFlow';
export * from '$lib/hooks/useUpdateNodeInternals'; export * from '$lib/hooks/useUpdateNodeInternals';
export * from '$lib/hooks/useConnection'; export * from '$lib/hooks/useConnection';
export * from '$lib/hooks/useNodesEdges'; export * from '$lib/hooks/useNodesEdges';
export * from '$lib/hooks/useHandleConnections';
export * from '$lib/hooks/useNodesData';
// types // types
export type { Edge, EdgeProps, EdgeTypes, DefaultEdgeOptions } from '$lib/types/edges'; export type {
Edge,
EdgeProps,
BezierEdgeProps,
SmoothStepEdgeProps,
StepEdgeProps,
StraightEdgeProps,
EdgeTypes,
DefaultEdgeOptions
} from '$lib/types/edges';
export type { HandleComponentProps, FitViewOptions } from '$lib/types/general'; export type { HandleComponentProps, FitViewOptions } from '$lib/types/general';
export type { Node, NodeTypes, DefaultNodeOptions } from '$lib/types/nodes'; export type { Node, NodeTypes, DefaultNodeOptions } from '$lib/types/nodes';
export type { SvelteFlowStore } from '$lib/store/types'; export type { SvelteFlowStore } from '$lib/store/types';
@@ -45,8 +45,8 @@
<svg <svg
class={cc(['svelte-flow__background', className])} class={cc(['svelte-flow__background', className])}
data-testid="svelte-flow__background" data-testid="svelte-flow__background"
style:--background-color-props={bgColor} style:--xy-background-color-props={bgColor}
style:--background-pattern-color-props={patternColor} style:--xy-background-pattern-color-props={patternColor}
> >
<pattern <pattern
id={patternId} id={patternId}
@@ -15,11 +15,11 @@
type="button" type="button"
on:click on:click
class={cc(['svelte-flow__controls-button', className])} class={cc(['svelte-flow__controls-button', className])}
style:--controls-button-background-color-props={bgColor} style:--xy-controls-button-background-color-props={bgColor}
style:--controls-button-background-color-hover-props={bgColorHover} style:--xy-controls-button-background-color-hover-props={bgColorHover}
style:--controls-button-color-props={color} style:--xy-controls-button-color-props={color}
style:--controls-button-color-hover-props={colorHover} style:--xy-controls-button-color-hover-props={colorHover}
style:--controls-button-border-color-props={borderColor} style:--xy-controls-button-border-color-props={borderColor}
{...$$restProps} {...$$restProps}
> >
<slot class="button-svg" /> <slot class="button-svg" />
@@ -94,10 +94,10 @@
viewBox="{x} {y} {viewboxWidth} {viewboxHeight}" viewBox="{x} {y} {viewboxWidth} {viewboxHeight}"
role="img" role="img"
aria-labelledby={labelledBy} aria-labelledby={labelledBy}
style:--minimap-background-color-props={bgColor} style:--xy-minimap-background-color-props={bgColor}
style:--minimap-mask-color-props={maskColor} style:--xy-minimap-mask-color-props={maskColor}
style:--minimap-mask-stroke-color-props={maskStrokeColor} style:--xy-minimap-mask-stroke-color-props={maskStrokeColor}
style:--minimap-mask-stroke-width-props={maskStrokeWidth} style:--xy-minimap-mask-stroke-width-props={maskStrokeWidth}
use:interactive={{ use:interactive={{
panZoom: $panZoom, panZoom: $panZoom,
viewport, viewport,
+13 -8
View File
@@ -192,15 +192,20 @@ export function createStore({
} }
function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) { function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) {
const nodeIdsToUnselect = (params?.nodes ? params.nodes : get(store.nodes)).map( const selectedNodeIds = (params?.nodes ? params.nodes : get(store.nodes))
(item) => item.id .filter((node) => node.selected)
); .map((node) => node.id);
const edgeIdsToUnselect = (params?.edges ? params.edges : get(store.edges)).map( const selectedEdgeIds = (params?.edges ? params.edges : get(store.edges))
(item) => item.id .filter((edge) => edge.selected)
); .map((edge) => edge.id);
store.nodes.update((ns) => ns.map(resetSelectedItem(nodeIdsToUnselect))); if (selectedNodeIds.length) {
store.edges.update((es) => es.map(resetSelectedItem(edgeIdsToUnselect))); store.nodes.update((ns) => ns.map(resetSelectedItem(selectedNodeIds)));
}
if (selectedEdgeIds.length) {
store.edges.update((es) => es.map(resetSelectedItem(selectedEdgeIds)));
}
} }
store.deleteKeyPressed.subscribe((deleteKeyPressed) => { store.deleteKeyPressed.subscribe((deleteKeyPressed) => {
+29 -13
View File
@@ -17,17 +17,26 @@ import {
type Viewport, type Viewport,
updateNodes, updateNodes,
getNodesBounds, getNodesBounds,
getViewportForBounds getViewportForBounds,
updateConnectionLookup,
type ConnectionLookup,
type OnConnect,
type OnConnectStart,
type OnConnectEnd
} from '@xyflow/system'; } from '@xyflow/system';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte'; import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import InputNode from '$lib/components/nodes/InputNode.svelte'; import InputNode from '$lib/components/nodes/InputNode.svelte';
import OutputNode from '$lib/components/nodes/OutputNode.svelte'; import OutputNode from '$lib/components/nodes/OutputNode.svelte';
import GroupNode from '$lib/components/nodes/GroupNode.svelte'; import GroupNode from '$lib/components/nodes/GroupNode.svelte';
import BezierEdge from '$lib/components/edges/BezierEdge.svelte';
import StraightEdge from '$lib/components/edges/StraightEdge.svelte'; import {
import SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte'; BezierEdgeInternal,
import StepEdge from '$lib/components/edges/StepEdge.svelte'; SmoothStepEdgeInternal,
StraightEdgeInternal,
StepEdgeInternal
} from '$lib/components/edges';
import type { import type {
NodeTypes, NodeTypes,
EdgeTypes, EdgeTypes,
@@ -35,7 +44,8 @@ import type {
Node, Node,
Edge, Edge,
FitViewOptions, FitViewOptions,
OnDelete OnDelete,
OnEdgeCreate
} from '$lib/types'; } from '$lib/types';
import { createNodesStore, createEdgesStore } from './utils'; import { createNodesStore, createEdgesStore } from './utils';
import { initConnectionProps, type ConnectionProps } from './derived-connection-props'; import { initConnectionProps, type ConnectionProps } from './derived-connection-props';
@@ -48,10 +58,10 @@ export const initialNodeTypes = {
}; };
export const initialEdgeTypes = { export const initialEdgeTypes = {
straight: StraightEdge, straight: StraightEdgeInternal,
smoothstep: SmoothStepEdge, smoothstep: SmoothStepEdgeInternal,
default: BezierEdge, default: BezierEdgeInternal,
step: StepEdge step: StepEdgeInternal
}; };
export const getInitialStore = ({ export const getInitialStore = ({
@@ -67,11 +77,12 @@ export const getInitialStore = ({
height?: number; height?: number;
fitView?: boolean; fitView?: boolean;
}) => { }) => {
const nodeLookup = new Map<string, Node>(); const nodeLookup = new Map();
const nextNodes = updateNodes(nodes, nodeLookup, { const nextNodes = updateNodes(nodes, nodeLookup, {
nodeOrigin: [0, 0], nodeOrigin: [0, 0],
elevateNodesOnSelect: false elevateNodesOnSelect: false
}); });
const connectionLookup = updateConnectionLookup(new Map(), edges);
let viewport: Viewport = { x: 0, y: 0, zoom: 1 }; let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
@@ -86,8 +97,9 @@ export const getInitialStore = ({
nodes: createNodesStore(nextNodes, nodeLookup), nodes: createNodesStore(nextNodes, nodeLookup),
nodeLookup: readable<Map<string, Node>>(nodeLookup), nodeLookup: readable<Map<string, Node>>(nodeLookup),
visibleNodes: readable<Node[]>([]), visibleNodes: readable<Node[]>([]),
edges: createEdgesStore(edges), edges: createEdgesStore(edges, connectionLookup),
edgeTree: readable<GroupedEdges<EdgeLayouted>[]>([]), edgeTree: readable<GroupedEdges<EdgeLayouted>[]>([]),
connectionLookup: readable<ConnectionLookup>(connectionLookup),
height: writable<number>(500), height: writable<number>(500),
width: writable<number>(500), width: writable<number>(500),
minZoom: writable<number>(0.5), minZoom: writable<number>(0.5),
@@ -130,6 +142,10 @@ export const getInitialStore = ({
lib: readable<string>('svelte'), lib: readable<string>('svelte'),
onlyRenderVisibleElements: writable<boolean>(false), onlyRenderVisibleElements: writable<boolean>(false),
onerror: writable<OnError>(devWarn), onerror: writable<OnError>(devWarn),
ondelete: writable<OnDelete>(undefined) ondelete: writable<OnDelete>(undefined),
onedgecreate: writable<OnEdgeCreate>(undefined),
onconnect: writable<OnConnect>(undefined),
onconnectstart: writable<OnConnectStart>(undefined),
onconnectend: writable<OnConnectEnd>(undefined)
}; };
}; };
+11 -1
View File
@@ -6,7 +6,13 @@ import {
type Writable, type Writable,
get get
} from 'svelte/store'; } from 'svelte/store';
import { updateNodes, type Viewport, type PanZoomInstance } from '@xyflow/system'; import {
updateNodes,
type Viewport,
type PanZoomInstance,
type ConnectionLookup,
updateConnectionLookup
} from '@xyflow/system';
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, Node } from '$lib/types'; import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, Node } from '$lib/types';
@@ -168,6 +174,7 @@ export const createNodesStore = (
export const createEdgesStore = ( export const createEdgesStore = (
edges: Edge[], edges: Edge[],
connectionLookup: ConnectionLookup,
defaultOptions?: DefaultEdgeOptions defaultOptions?: DefaultEdgeOptions
): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => { ): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => {
const { subscribe, set, update } = writable<Edge[]>([]); const { subscribe, set, update } = writable<Edge[]>([]);
@@ -176,6 +183,9 @@ export const createEdgesStore = (
const _set: typeof set = (eds: Edge[]) => { const _set: typeof set = (eds: Edge[]) => {
const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds; const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;
updateConnectionLookup(connectionLookup, nextEdges);
value = nextEdges; value = nextEdges;
set(value); set(value);
}; };
+30 -2
View File
@@ -5,7 +5,9 @@ import type {
BezierPathOptions, BezierPathOptions,
DefaultEdgeOptionsBase, DefaultEdgeOptionsBase,
EdgePosition, EdgePosition,
SmoothStepPathOptions SmoothStepPathOptions,
Optional,
StepPathOptions
} from '@xyflow/system'; } from '@xyflow/system';
import type { Node } from '$lib/types'; import type { Node } from '$lib/types';
@@ -29,6 +31,7 @@ type BezierEdgeType<T> = DefaultEdge<T> & {
type StepEdgeType<T> = DefaultEdge<T> & { type StepEdgeType<T> = DefaultEdge<T> & {
type: 'step'; type: 'step';
pathOptions?: StepPathOptions;
}; };
export type Edge<T = any> = export type Edge<T = any> =
@@ -37,7 +40,7 @@ export type Edge<T = any> =
| BezierEdgeType<T> | BezierEdgeType<T>
| StepEdgeType<T>; | StepEdgeType<T>;
export type EdgeProps = Omit<Edge, 'sourceHandle' | 'targetHandle'> & export type EdgeProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHandle' | 'type'> &
EdgePosition & { EdgePosition & {
markerStart?: string; markerStart?: string;
markerEnd?: string; markerEnd?: string;
@@ -45,6 +48,31 @@ export type EdgeProps = Omit<Edge, 'sourceHandle' | 'targetHandle'> &
targetHandleId?: string | null; targetHandleId?: string | null;
}; };
export type EdgeComponentProps<T = any> = Optional<
Omit<
EdgeProps<T>,
'source' | 'target' | 'sourceHandleId' | 'targetHandleId' | 'animated' | 'selected' | 'data'
>,
'id'
>;
export type BezierEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: BezierPathOptions;
};
export type SmoothStepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: SmoothStepPathOptions;
};
export type StepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: StepPathOptions;
};
export type StraightEdgeProps<T = any> = Omit<
EdgeComponentProps<T>,
'sourcePosition' | 'targetPosition'
>;
export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>; export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>;
export type DefaultEdgeOptions = Omit<DefaultEdgeOptionsBase<Edge>, 'focusable'>; export type DefaultEdgeOptions = Omit<DefaultEdgeOptionsBase<Edge>, 'focusable'>;
+5 -1
View File
@@ -4,7 +4,8 @@ import type {
HandleType, HandleType,
Position, Position,
XYPosition, XYPosition,
ConnectingHandle ConnectingHandle,
Connection
} from '@xyflow/system'; } from '@xyflow/system';
import type { Node } from './nodes'; import type { Node } from './nodes';
@@ -30,8 +31,11 @@ export type HandleComponentProps = {
isConnectable?: boolean; isConnectable?: boolean;
isConnectableStart?: boolean; isConnectableStart?: boolean;
isConnectableEnd?: boolean; isConnectableEnd?: boolean;
onconnect?: (connections: Connection[]) => void;
ondisconnect?: (connections: Connection[]) => void;
}; };
export type FitViewOptions = FitViewOptionsBase<Node>; export type FitViewOptions = FitViewOptionsBase<Node>;
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void; export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;
export type OnEdgeCreate = (connection: Connection) => Edge | Connection | void;
+2 -2
View File
@@ -10,8 +10,8 @@ import {
import type { Edge, Node } from '$lib/types'; import type { Edge, Node } from '$lib/types';
export const isNode = isNodeBase<Node, Edge>; export const isNode = isNodeBase<Node>;
export const isEdge = isEdgeBase<Node, Edge>; export const isEdge = isEdgeBase<Edge>;
export const getOutgoers = getOutgoersBase<Node, Edge>; export const getOutgoers = getOutgoersBase<Node, Edge>;
export const getIncomers = getIncomersBase<Node, Edge>; export const getIncomers = getIncomersBase<Node, Edge>;
export const addEdge = addEdgeBase<Edge>; export const addEdge = addEdgeBase<Edge>;
+2 -1
View File
@@ -8,7 +8,8 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true "strict": true,
"noErrorTruncation": true
} }
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@xyflow/system", "name": "@xyflow/system",
"version": "0.0.11", "version": "0.0.12",
"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",
+12 -12
View File
@@ -1,38 +1,38 @@
.xy-flow { .xy-flow {
--node-border-default: 1px solid #bbb; --xy-node-border-default: 1px solid #bbb;
--node-border-selected-default: 1px solid #555; --xy-node-border-selected-default: 1px solid #555;
--handle-background-color-default: #333; --xy-handle-background-color-default: #333;
--selection-background-color-default: rgba(150, 150, 180, 0.1); --xy-selection-background-color-default: rgba(150, 150, 180, 0.1);
--selection-border-default: 1px dotted rgba(155, 155, 155, 0.8); --xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);
} }
.xy-flow.dark { .xy-flow.dark {
--node-color-default: #f8f8f8; --xy-node-color-default: #f8f8f8;
} }
.xy-flow__handle { .xy-flow__handle {
background-color: var(--handle-background-color, var(--handle-background-color-default)); background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
} }
.xy-flow__node-input, .xy-flow__node-input,
.xy-flow__node-default, .xy-flow__node-default,
.xy-flow__node-output, .xy-flow__node-output,
.xy-flow__node-group { .xy-flow__node-group {
border: var(--node-border, var(--node-border-default)); border: var(--xy-node-border, var(--xy-node-border-default));
color: var(--node-color, var(--node-color-default)); color: var(--xy-node-color, var(--xy-node-color-default));
&.selected, &.selected,
&:focus, &:focus,
&:focus-visible { &:focus-visible {
outline: none; outline: none;
border: var(--node-border-selected, var(--node-border-selected-default)); border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));
} }
} }
.xy-flow__nodesselection-rect, .xy-flow__nodesselection-rect,
.xy-flow__selection { .xy-flow__selection {
background: var(--selection-background-color, var(--selection-background-color-default)); background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
border: var(--selection-border, var(--selection-border-default)); border: var(--xy-selection-border, var(--xy-selection-border-default));
} }
+56 -52
View File
@@ -1,51 +1,55 @@
/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */ /* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */
.xy-flow { .xy-flow {
--edge-stroke-default: #b1b1b7; --xy-edge-stroke-default: #b1b1b7;
--edge-stroke-width-default: 1; --xy-edge-stroke-width-default: 1;
--edge-stroke-selected-default: #555; --xy-edge-stroke-selected-default: #555;
--connectionline-stroke-default: #b1b1b7; --xy-connectionline-stroke-default: #b1b1b7;
--connectionline-stroke-width-default: 1; --xy-connectionline-stroke-width-default: 1;
--attribution-background-color-default: rgba(255, 255, 255, 0.5); --xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);
--minimap-background-color-default: #fff; --xy-minimap-background-color-default: #fff;
--minimap-mask-background-color-default: rgb(240, 240, 240, 0.6); --xy-minimap-mask-background-color-default: rgb(240, 240, 240, 0.6);
--minimap-node-background-color-default: #e2e2e2; --xy-minimap-node-background-color-default: #e2e2e2;
--minimap-node-stroke-color-default: transparent; --xy-minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2; --xy-minimap-node-stroke-width-default: 2;
--background-color-default: transparent; --xy-background-color-default: transparent;
--background-pattern-dots-color-default: #91919a; --xy-background-pattern-dots-color-default: #91919a;
--background-pattern-lines-color-default: #eee; --xy-background-pattern-lines-color-default: #eee;
--background-pattern-cross-color-default: #e2e2e2; --xy-background-pattern-cross-color-default: #e2e2e2;
} }
.xy-flow.dark { .xy-flow.dark {
--edge-stroke-default: #3c3c3c; --xy-edge-stroke-default: #3e3e3e;
--edge-stroke-width-default: 1; --xy-edge-stroke-width-default: 1;
--edge-stroke-selected-default: #727272; --xy-edge-stroke-selected-default: #727272;
--connectionline-stroke-default: #b1b1b7; --xy-connectionline-stroke-default: #b1b1b7;
--connectionline-stroke-width-default: 1; --xy-connectionline-stroke-width-default: 1;
--attribution-background-color-default: rgba(150, 150, 150, 0.25); --xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);
--minimap-background-color-default: #141414; --xy-minimap-background-color-default: #141414;
--minimap-mask-background-color-default: rgb(60, 60, 60, 0.6); --xy-minimap-mask-background-color-default: rgb(60, 60, 60, 0.6);
--minimap-node-background-color-default: #2b2b2b; --xy-minimap-node-background-color-default: #2b2b2b;
--minimap-node-stroke-color-default: transparent; --xy-minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2; --xy-minimap-node-stroke-width-default: 2;
--background-color-default: #141414; --xy-background-color-default: #141414;
--background-pattern-dots-color-default: #777; --xy-background-pattern-dots-color-default: #777;
--background-pattern-lines-color-default: #777; --xy-background-pattern-lines-color-default: #777;
--background-pattern-cross-color-default: #777; --xy-background-pattern-cross-color-default: #777;
} }
.xy-flow { .xy-flow {
background-color: var(--background-color-props, var(--background-color-default, 'transparent')); background-color: var(--xy-background-color, var(--xy-background-color-default));
}
.xy-flow__background {
background-color: var(--xy-background-color, var(--xy-background-color-props, var(--xy-background-color-default)));
} }
.xy-flow__container { .xy-flow__container {
@@ -94,14 +98,14 @@
} }
.xy-flow__edge-path { .xy-flow__edge-path {
stroke: var(--edge-stroke, var(--edge-stroke-default)); stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
stroke-width: var(--edge-stroke-width, var(--edge-stroke-width-default)); stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));
fill: none; fill: none;
} }
.xy-flow__connection-path { .xy-flow__connection-path {
stroke: var(--connectionline-stroke, var(--connectionline-stroke-default)); stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));
stroke-width: var(--connectionline-stroke-width, var(--connectionline-stroke-width-default)); stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));
fill: none; fill: none;
} }
@@ -132,7 +136,7 @@
&.selected .xy-flow__edge-path, &.selected .xy-flow__edge-path,
&:focus .xy-flow__edge-path, &:focus .xy-flow__edge-path,
&:focus-visible .xy-flow__edge-path { &:focus-visible .xy-flow__edge-path {
stroke: var(--edge-stroke-selected, var(--edge-stroke-selected-default)); stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
} }
&-textwrapper { &-textwrapper {
@@ -266,7 +270,7 @@
.xy-flow__attribution { .xy-flow__attribution {
font-size: 10px; font-size: 10px;
background: var(--attribution-background-color, var(--attribution-background-color-default)); background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));
padding: 2px 3px; padding: 2px 3px;
margin: 0; margin: 0;
@@ -293,27 +297,27 @@
} }
.xy-flow__minimap { .xy-flow__minimap {
background: var(--minimap-background-color, var(--minimap-background-color-default)); background: var(--xy-minimap-background-color, var(--xy-minimap-background-color-default));
&-mask { &-mask {
fill: var( fill: var(
--minimap-mask-background-color-props, --xy-minimap-mask-background-color-props,
var(--minimap-mask-background-color, var(--minimap-mask-background-color-default)) var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))
); );
} }
&-node { &-node {
fill: var( fill: var(
--minimap-node-background-color-props, --xy-minimap-node-background-color-props,
var(--minimap-node-background-color, var(--minimap-node-background-color-default)) var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))
); );
stroke: var( stroke: var(
--minimap-node-stroke-color-props, --xy-minimap-node-stroke-color-props,
var(--minimap-node-stroke-color, var(--minimap-node-stroke-color-default)) var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))
); );
stroke-width: var( stroke-width: var(
--minimap-node-stroke-width-props, --xy-minimap-node-stroke-width-props,
var(--minimap-node-stroke-width, var(--minimap-node-stroke-width-default)) var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))
); );
} }
} }
@@ -326,22 +330,22 @@
.xy-flow__background-pattern { .xy-flow__background-pattern {
&.dots { &.dots {
fill: var( fill: var(
--background-pattern-color-props, --xy-background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-dots-color-default)) var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))
); );
} }
&.lines { &.lines {
stroke: var( stroke: var(
--background-pattern-color-props, --xy-background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-lines-color-default)) var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))
); );
} }
&.cross { &.cross {
stroke: var( stroke: var(
--background-pattern-color-props, --xy-background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-cross-color-default)) var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))
); );
} }
} }
+56 -53
View File
@@ -1,46 +1,46 @@
.xy-flow { .xy-flow {
--node-color-default: inherit; --xy-node-color-default: inherit;
--node-border-default: 1px solid #1a192b; --xy-node-border-default: 1px solid #1a192b;
--node-background-color-default: #fff; --xy-node-background-color-default: #fff;
--node-group-background-color-default: rgba(240, 240, 240, 0.25); --xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08); --xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
--node-boxshadow-selected-default: 0 0 0 0.5px #1a192b; --xy-node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
--node-border-radius-default: 3px; --xy-node-border-radius-default: 3px;
--handle-background-color-default: #1a192b; --xy-handle-background-color-default: #1a192b;
--handle-border-color-default: #fff; --xy-handle-border-color-default: #fff;
--selection-background-color-default: rgba(0, 89, 220, 0.08); --xy-selection-background-color-default: rgba(0, 89, 220, 0.08);
--selection-border-default: 1px dotted rgba(0, 89, 220, 0.8); --xy-selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
--controls-button-background-color-default: #fefefe; --xy-controls-button-background-color-default: #fefefe;
--controls-button-background-color-hover-default: #f4f4f4; --xy-controls-button-background-color-hover-default: #f4f4f4;
--controls-button-color-default: inherit; --xy-controls-button-color-default: inherit;
--controls-button-color-hover-default: inherit; --xy-controls-button-color-hover-default: inherit;
--controls-button-border-color-default: #eee; --xy-controls-button-border-color-default: #eee;
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08); --xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
} }
.xy-flow.dark { .xy-flow.dark {
--node-color-default: #f8f8f8; --xy-node-color-default: #f8f8f8;
--node-border-default: 1px solid #3c3c3c; --xy-node-border-default: 1px solid #3c3c3c;
--node-background-color-default: #1e1e1e; --xy-node-background-color-default: #1e1e1e;
--node-group-background-color-default: rgba(240, 240, 240, 0.25); --xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08); --xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
--node-boxshadow-selected-default: 0 0 0 0.5px #999; --xy-node-boxshadow-selected-default: 0 0 0 0.5px #999;
--handle-background-color-default: #bebebe; --xy-handle-background-color-default: #bebebe;
--handle-border-color-default: #1e1e1e; --xy-handle-border-color-default: #1e1e1e;
--selection-background-color-default: rgba(200, 200, 220, 0.08); --xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
--selection-border-default: 1px dotted rgba(200, 200, 220, 0.8); --xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
--controls-button-background-color-default: #2b2b2b; --xy-controls-button-background-color-default: #2b2b2b;
--controls-button-background-color-hover-default: #3e3e3e; --xy-controls-button-background-color-hover-default: #3e3e3e;
--controls-button-color-default: #f8f8f8; --xy-controls-button-color-default: #f8f8f8;
--controls-button-color-hover-default: #fff; --xy-controls-button-color-hover-default: #fff;
--controls-button-border-color-default: #5b5b5b; --xy-controls-button-border-color-default: #5b5b5b;
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08); --xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
} }
.xy-flow__edge { .xy-flow__edge {
@@ -67,35 +67,35 @@
.xy-flow__node-output, .xy-flow__node-output,
.xy-flow__node-group { .xy-flow__node-group {
padding: 10px; padding: 10px;
border-radius: var(--node-border-radius, var(--node-border-radius-default)); border-radius: var(--xy-node-border-radius, var(--xy-node-border-radius-default));
width: 150px; width: 150px;
font-size: 12px; font-size: 12px;
color: var(--node-color, var(--node-color-default)); color: var(--xy-node-color, var(--xy-node-color-default));
text-align: center; text-align: center;
border: var(--node-border, var(--node-border-default)); border: var(--xy-node-border, var(--xy-node-border-default));
background-color: var(--node-background-color, var(--node-background-color-default)); background-color: var(--xy-node-background-color, var(--xy-node-background-color-default));
&.selectable { &.selectable {
&:hover { &:hover {
box-shadow: var(--node-boxshadow-hover, var(--node-boxshadow-hover-default)); box-shadow: var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default));
} }
&.selected, &.selected,
&:focus, &:focus,
&:focus-visible { &:focus-visible {
box-shadow: var(--node-boxshadow-selected, var(--node-boxshadow-selected-default)); box-shadow: var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default));
} }
} }
} }
.xy-flow__node-group { .xy-flow__node-group {
background-color: var(--node-group-background-color, var(--node-group-background-color-default)); background-color: var(--xy-node-group-background-color, var(--xy-node-group-background-color-default));
} }
.xy-flow__nodesselection-rect, .xy-flow__nodesselection-rect,
.xy-flow__selection { .xy-flow__selection {
background: var(--selection-background-color, var(--selection-background-color-default)); background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
border: var(--selection-border, var(--selection-border-default)); border: var(--xy-selection-border, var(--xy-selection-border-default));
&:focus, &:focus,
&:focus-visible { &:focus-visible {
@@ -106,34 +106,37 @@
.xy-flow__handle { .xy-flow__handle {
width: 6px; width: 6px;
height: 6px; height: 6px;
background-color: var(--handle-background-color, var(--handle-background-color-default)); background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
border: 1px solid var(--handle-border-color, var(--handle-border-color-default)); border: 1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));
border-radius: 100%; border-radius: 100%;
} }
.xy-flow__controls { .xy-flow__controls {
box-shadow: var(--controls-box-shadow, var(--controls-box-shadow-default)); box-shadow: var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default));
&-button { &-button {
border: none; border: none;
background: var(--controls-button-background-color, var(--controls-button-background-color-default)); background: var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));
border-bottom: 1px solid border-bottom: 1px solid
var( var(
--controls-button-border-color-props, --xy-controls-button-border-color-props,
var(--controls-button-border-color, var(--controls-button-border-color-default)) var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default))
); );
color: var(--controls-button-color-props, var(--controls-button-color, var(--controls-button-color-default))); color: var(
--xy-controls-button-color-props,
var(--xy-controls-button-color, var(--xy-controls-button-color-default))
);
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
&:hover { &:hover {
background: var( background: var(
--controls-button-background-color-hover-props, --xy-controls-button-background-color-hover-props,
var(--controls-button-background-color-hover, var(--controls-button-background-color-hover-default)) var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default))
); );
color: var( color: var(
--controls-button-color-hover-props, --xy-controls-button-color-hover-props,
var(--controls-button-color-hover, var(--controls-button-color-hover-default)) var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default))
); );
} }
+4
View File
@@ -27,6 +27,10 @@ export type SmoothStepPathOptions = {
borderRadius?: number; borderRadius?: number;
}; };
export type StepPathOptions = {
offset?: number;
};
export type BezierPathOptions = { export type BezierPathOptions = {
curvature?: number; curvature?: number;
}; };
+4 -2
View File
@@ -22,8 +22,8 @@ export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => vo
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void; export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
export type Connection = { export type Connection = {
source: string | null; source: string;
target: string | null; target: string;
sourceHandle: string | null; sourceHandle: string | null;
targetHandle: string | null; targetHandle: string | null;
}; };
@@ -139,3 +139,5 @@ export type UpdateConnection = (params: {
export type ColorModeClass = 'light' | 'dark'; export type ColorModeClass = 'light' | 'dark';
export type ColorMode = ColorModeClass | 'system'; export type ColorMode = ColorModeClass | 'system';
export type ConnectionLookup = Map<string, Map<string, Connection>>;
+2
View File
@@ -1,3 +1,5 @@
import type { Optional } from '../utils/types';
export enum Position { export enum Position {
Left = 'left', Left = 'left',
Top = 'top', Top = 'top',
+53
View File
@@ -0,0 +1,53 @@
import { Connection } from '../types';
/**
* @internal
*/
export function areConnectionMapsEqual(a?: Map<string, Connection>, b?: Map<string, Connection>) {
if (!a && !b) {
return true;
}
if (!a || !b || a.size !== b.size) {
return false;
}
if (!a.size && !b.size) {
return true;
}
for (const key of a.keys()) {
if (!b.has(key)) {
return false;
}
}
return true;
}
/**
* We call the callback for all connections in a that are not in b
*
* @internal
*/
export function handleConnectionChange(
a: Map<string, Connection>,
b: Map<string, Connection>,
cb?: (diff: Connection[]) => void
) {
if (!cb) {
return;
}
const diff: Connection[] = [];
a.forEach((connection, key) => {
if (!b?.has(key)) {
diff.push(connection);
}
});
if (diff.length) {
cb(diff);
}
}
+9 -1
View File
@@ -112,7 +112,7 @@ export function isEdgeVisible({ sourceNode, targetNode, width, height, transform
} }
const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection | EdgeBase): string => const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection | EdgeBase): string =>
`xyflow__edge-${source}${sourceHandle || ''}-${target}${targetHandle || ''}`; `xy-edge__${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;
const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => { const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => {
return edges.some( return edges.some(
@@ -148,6 +148,14 @@ export const addEdgeBase = <EdgeType extends EdgeBase>(
return edges; return edges;
} }
if (edge.sourceHandle === null) {
delete edge.sourceHandle;
}
if (edge.targetHandle === null) {
delete edge.targetHandle;
}
return edges.concat(edge); return edges.concat(edge);
}; };
+4 -7
View File
@@ -11,7 +11,6 @@ import {
getViewportForBounds, getViewportForBounds,
} from './general'; } from './general';
import { import {
type Connection,
type Transform, type Transform,
type XYPosition, type XYPosition,
type Rect, type Rect,
@@ -26,13 +25,11 @@ import {
} from '../types'; } from '../types';
import { errorMessages } from '../constants'; import { errorMessages } from '../constants';
export const isEdgeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>( export const isEdgeBase = <EdgeType extends EdgeBase = EdgeBase>(element: any): element is EdgeType =>
element: NodeType | Connection | EdgeType 'id' in element && 'source' in element && 'target' in element;
): element is EdgeType => 'id' in element && 'source' in element && 'target' in element;
export const isNodeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>( export const isNodeBase = <NodeType extends NodeBase = NodeBase>(element: any): element is NodeType =>
element: NodeType | Connection | EdgeType 'id' in element && !('source' in element) && !('target' in element);
): element is NodeType => 'id' in element && !('source' in element) && !('target' in element);
export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>( export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
node: NodeType | { id: string }, node: NodeType | { id: string },
+2
View File
@@ -1,3 +1,4 @@
export * from './connections';
export * from './dom'; export * from './dom';
export * from './edges'; export * from './edges';
export * from './graph'; export * from './graph';
@@ -5,3 +6,4 @@ export * from './general';
export * from './marker'; export * from './marker';
export * from './node-toolbar'; export * from './node-toolbar';
export * from './store'; export * from './store';
export * from './types';
+25 -1
View File
@@ -9,6 +9,8 @@ import {
Transform, Transform,
XYPosition, XYPosition,
XYZPosition, XYZPosition,
ConnectionLookup,
EdgeBase,
} from '../types'; } from '../types';
import { getDimensions, getHandleBounds } from './dom'; import { getDimensions, getHandleBounds } from './dom';
import { isNumeric } from './general'; import { isNumeric } from './general';
@@ -71,11 +73,13 @@ export function updateNodes<NodeType extends NodeBase>(
defaults: {}, defaults: {},
} }
): NodeType[] { ): NodeType[] {
const tmpLookup = new Map(nodeLookup);
nodeLookup.clear();
const parentNodes: ParentNodes = {}; const parentNodes: ParentNodes = {};
const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0; const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0;
const nextNodes = nodes.map((n) => { const nextNodes = nodes.map((n) => {
const currentStoreNode = nodeLookup.get(n.id); const currentStoreNode = tmpLookup.get(n.id);
const node: NodeType = { const node: NodeType = {
...options.defaults, ...options.defaults,
...n, ...n,
@@ -233,3 +237,23 @@ export function panBy({
return transformChanged; return transformChanged;
} }
export function updateConnectionLookup(lookup: ConnectionLookup, edges: EdgeBase[]) {
lookup.clear();
edges.forEach(({ source, target, sourceHandle = null, targetHandle = null }) => {
if (source && target) {
const sourceKey = `${source}-source-${sourceHandle}`;
const targetKey = `${target}-target-${targetHandle}`;
const prevSource = lookup.get(sourceKey) || new Map();
const prevTarget = lookup.get(targetKey) || new Map();
const connection = { source, target, sourceHandle, targetHandle };
lookup.set(sourceKey, prevSource.set(`${target}-${targetHandle}`, connection));
lookup.set(targetKey, prevTarget.set(`${source}-${sourceHandle}`, connection));
}
});
return lookup;
}
+7 -5
View File
@@ -58,12 +58,10 @@ export type XYHandleInstance = {
type Result = { type Result = {
handleDomNode: Element | null; handleDomNode: Element | null;
isValid: boolean; isValid: boolean;
connection: Connection; connection: Connection | null;
endHandle: ConnectingHandle | null; endHandle: ConnectingHandle | null;
}; };
const nullConnection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null };
const alwaysValid = () => true; const alwaysValid = () => true;
let connectionStartHandle: ConnectingHandle | null = null; let connectionStartHandle: ConnectingHandle | null = null;
@@ -197,7 +195,7 @@ function onPointerDown(
return resetRecentHandle(prevActiveHandle, lib); return resetRecentHandle(prevActiveHandle, lib);
} }
if (connection.source !== connection.target && handleDomNode) { if (connection?.source !== connection?.target && handleDomNode) {
resetRecentHandle(prevActiveHandle, lib); resetRecentHandle(prevActiveHandle, lib);
prevActiveHandle = handleDomNode; prevActiveHandle = handleDomNode;
handleDomNode.classList.add('connecting', `${lib}-flow__handle-connecting`); handleDomNode.classList.add('connecting', `${lib}-flow__handle-connecting`);
@@ -269,7 +267,7 @@ function isValidHandle(
const result: Result = { const result: Result = {
handleDomNode: handleToCheck, handleDomNode: handleToCheck,
isValid: false, isValid: false,
connection: nullConnection, connection: null,
endHandle: null, endHandle: null,
}; };
@@ -280,6 +278,10 @@ function isValidHandle(
const connectable = handleToCheck.classList.contains('connectable'); const connectable = handleToCheck.classList.contains('connectable');
const connectableEnd = handleToCheck.classList.contains('connectableend'); const connectableEnd = handleToCheck.classList.contains('connectableend');
if (!handleNodeId) {
return result;
}
const connection: Connection = { const connection: Connection = {
source: isTarget ? handleNodeId : fromNodeId, source: isTarget ? handleNodeId : fromNodeId,
sourceHandle: isTarget ? handleId : fromHandleId, sourceHandle: isTarget ? handleId : fromHandleId,
+145 -43
View File
@@ -61,10 +61,10 @@ importers:
dependencies: dependencies:
'@astrojs/react': '@astrojs/react':
specifier: ^3.0.2 specifier: ^3.0.2
version: registry.npmjs.org/@astrojs/react@3.0.2(@types/react-dom@18.2.8)(@types/react@18.2.24)(react-dom@18.2.0)(react@18.2.0)(vite@4.5.0) version: registry.npmjs.org/@astrojs/react@3.0.2(@types/react-dom@18.2.8)(@types/react@18.2.24)(react-dom@18.2.0)(react@18.2.0)(vite@4.5.1)
'@astrojs/svelte': '@astrojs/svelte':
specifier: ^4.0.2 specifier: ^4.0.2
version: registry.npmjs.org/@astrojs/svelte@4.0.2(astro@3.2.2)(svelte@4.2.1)(typescript@5.2.2)(vite@4.5.0) version: registry.npmjs.org/@astrojs/svelte@4.0.2(astro@3.2.2)(svelte@4.2.1)(typescript@5.3.3)(vite@4.5.1)
'@types/react': '@types/react':
specifier: ^18.2.24 specifier: ^18.2.24
version: registry.npmjs.org/@types/react@18.2.24 version: registry.npmjs.org/@types/react@18.2.24
@@ -291,8 +291,8 @@ importers:
packages/svelte: packages/svelte:
dependencies: dependencies:
'@svelte-put/shortcut': '@svelte-put/shortcut':
specifier: ^3.0.0 specifier: ^3.1.0
version: registry.npmjs.org/@svelte-put/shortcut@3.0.0 version: registry.npmjs.org/@svelte-put/shortcut@3.1.0
'@xyflow/system': '@xyflow/system':
specifier: workspace:* specifier: workspace:*
version: link:../system version: link:../system
@@ -305,7 +305,7 @@ importers:
version: registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6) version: registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6)
'@sveltejs/kit': '@sveltejs/kit':
specifier: ^1.22.6 specifier: ^1.22.6
version: registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.0) version: registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.1)
'@sveltejs/package': '@sveltejs/package':
specifier: ^2.2.1 specifier: ^2.2.1
version: registry.npmjs.org/@sveltejs/package@2.2.1(svelte@4.2.1)(typescript@5.1.3) version: registry.npmjs.org/@sveltejs/package@2.2.1(svelte@4.2.1)(typescript@5.1.3)
@@ -417,7 +417,7 @@ importers:
dependencies: dependencies:
'@playwright/experimental-ct-react': '@playwright/experimental-ct-react':
specifier: ^1.39.0 specifier: ^1.39.0
version: registry.npmjs.org/@playwright/experimental-ct-react@1.39.0(@types/node@18.7.16)(vite@4.5.0) version: registry.npmjs.org/@playwright/experimental-ct-react@1.39.0(@types/node@18.7.16)(vite@4.5.1)
'@types/react': '@types/react':
specifier: ^18.2.31 specifier: ^18.2.31
version: registry.npmjs.org/@types/react@18.2.31 version: registry.npmjs.org/@types/react@18.2.31
@@ -551,7 +551,7 @@ packages:
prismjs: registry.npmjs.org/prismjs@1.29.0 prismjs: registry.npmjs.org/prismjs@1.29.0
dev: false dev: false
registry.npmjs.org/@astrojs/react@3.0.2(@types/react-dom@18.2.8)(@types/react@18.2.24)(react-dom@18.2.0)(react@18.2.0)(vite@4.5.0): registry.npmjs.org/@astrojs/react@3.0.2(@types/react-dom@18.2.8)(@types/react@18.2.24)(react-dom@18.2.0)(react@18.2.0)(vite@4.5.1):
resolution: {integrity: sha512-aooNIuQxTg+IWGMZPuIEwBeBi4/TCPCMsr3714zuLjAjukVd5ZrX/bCNxJqDWU4HNwUm4XFU1OhcEvYOHa5uMQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@astrojs/react/-/react-3.0.2.tgz} resolution: {integrity: sha512-aooNIuQxTg+IWGMZPuIEwBeBi4/TCPCMsr3714zuLjAjukVd5ZrX/bCNxJqDWU4HNwUm4XFU1OhcEvYOHa5uMQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@astrojs/react/-/react-3.0.2.tgz}
id: registry.npmjs.org/@astrojs/react/3.0.2 id: registry.npmjs.org/@astrojs/react/3.0.2
name: '@astrojs/react' name: '@astrojs/react'
@@ -565,7 +565,7 @@ packages:
dependencies: dependencies:
'@types/react': registry.npmjs.org/@types/react@18.2.24 '@types/react': registry.npmjs.org/@types/react@18.2.24
'@types/react-dom': registry.npmjs.org/@types/react-dom@18.2.8 '@types/react-dom': registry.npmjs.org/@types/react-dom@18.2.8
'@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react@4.1.1(vite@4.5.0) '@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react@4.1.1(vite@4.5.1)
react: registry.npmjs.org/react@18.2.0 react: registry.npmjs.org/react@18.2.0
react-dom: registry.npmjs.org/react-dom@18.2.0(react@18.2.0) react-dom: registry.npmjs.org/react-dom@18.2.0(react@18.2.0)
ultrahtml: registry.npmjs.org/ultrahtml@1.5.2 ultrahtml: registry.npmjs.org/ultrahtml@1.5.2
@@ -574,7 +574,7 @@ packages:
- vite - vite
dev: false dev: false
registry.npmjs.org/@astrojs/svelte@4.0.2(astro@3.2.2)(svelte@4.2.1)(typescript@5.2.2)(vite@4.5.0): registry.npmjs.org/@astrojs/svelte@4.0.2(astro@3.2.2)(svelte@4.2.1)(typescript@5.3.3)(vite@4.5.1):
resolution: {integrity: sha512-XB9Sexq+iW5aUpctDk6zuKHbWIAuPlAnZKbfgaS9VOaOUtx1t12crP9YoKEVcTifXYgoRuWWfeEAm2I8pYlLIQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@astrojs/svelte/-/svelte-4.0.2.tgz} resolution: {integrity: sha512-XB9Sexq+iW5aUpctDk6zuKHbWIAuPlAnZKbfgaS9VOaOUtx1t12crP9YoKEVcTifXYgoRuWWfeEAm2I8pYlLIQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@astrojs/svelte/-/svelte-4.0.2.tgz}
id: registry.npmjs.org/@astrojs/svelte/4.0.2 id: registry.npmjs.org/@astrojs/svelte/4.0.2
name: '@astrojs/svelte' name: '@astrojs/svelte'
@@ -584,10 +584,10 @@ packages:
astro: ^3.0.11 astro: ^3.0.11
svelte: ^3.55.0 || ^4.0.0 svelte: ^3.55.0 || ^4.0.0
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.0) '@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.1)
astro: registry.npmjs.org/astro@3.2.2 astro: registry.npmjs.org/astro@3.2.2
svelte: registry.npmjs.org/svelte@4.2.1 svelte: registry.npmjs.org/svelte@4.2.1
svelte2tsx: registry.npmjs.org/svelte2tsx@0.6.23(svelte@4.2.1)(typescript@5.2.2) svelte2tsx: registry.npmjs.org/svelte2tsx@0.6.23(svelte@4.2.1)(typescript@5.3.3)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
- typescript - typescript
@@ -1938,7 +1938,7 @@ packages:
- terser - terser
dev: false dev: false
registry.npmjs.org/@playwright/experimental-ct-react@1.39.0(@types/node@18.7.16)(vite@4.5.0): registry.npmjs.org/@playwright/experimental-ct-react@1.39.0(@types/node@18.7.16)(vite@4.5.1):
resolution: {integrity: sha512-6GaDVVo6x8P9Jdw3yPbVaEP59nesRsETn3kznHAy+2493VsP3IaVATat2G28z0Sivf/K9Tkh5xRYjiawN0ebgw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@playwright/experimental-ct-react/-/experimental-ct-react-1.39.0.tgz} resolution: {integrity: sha512-6GaDVVo6x8P9Jdw3yPbVaEP59nesRsETn3kznHAy+2493VsP3IaVATat2G28z0Sivf/K9Tkh5xRYjiawN0ebgw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@playwright/experimental-ct-react/-/experimental-ct-react-1.39.0.tgz}
id: registry.npmjs.org/@playwright/experimental-ct-react/1.39.0 id: registry.npmjs.org/@playwright/experimental-ct-react/1.39.0
name: '@playwright/experimental-ct-react' name: '@playwright/experimental-ct-react'
@@ -1947,7 +1947,7 @@ packages:
hasBin: true hasBin: true
dependencies: dependencies:
'@playwright/experimental-ct-core': registry.npmjs.org/@playwright/experimental-ct-core@1.39.0(@types/node@18.7.16) '@playwright/experimental-ct-core': registry.npmjs.org/@playwright/experimental-ct-core@1.39.0(@types/node@18.7.16)
'@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react@4.1.1(vite@4.5.0) '@vitejs/plugin-react': registry.npmjs.org/@vitejs/plugin-react@4.1.1(vite@4.5.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@@ -2120,10 +2120,10 @@ packages:
version: 2.0.0 version: 2.0.0
dev: true dev: true
registry.npmjs.org/@svelte-put/shortcut@3.0.0: registry.npmjs.org/@svelte-put/shortcut@3.1.0:
resolution: {integrity: sha512-nZg3pwpTi9wUsvQPlqOzEsxZcF2jmY5j+VBq/20IUjjd2OpM92XqZAga0PCCjE6OuEobOt58UMnC2QZgOvk0tQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-3.0.0.tgz} resolution: {integrity: sha512-EWMEDkZ0+O3yMhb9yrqe5UYisV9CNRKX6Pl/JW3x62t74CiN+3COu1L9NzZUG0omagc2Z3J14PZNYxs77IC9NA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@svelte-put/shortcut/-/shortcut-3.1.0.tgz}
name: '@svelte-put/shortcut' name: '@svelte-put/shortcut'
version: 3.0.0 version: 3.1.0
dev: false dev: false
registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6): registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6):
@@ -2134,7 +2134,7 @@ packages:
peerDependencies: peerDependencies:
'@sveltejs/kit': ^1.0.0 '@sveltejs/kit': ^1.0.0
dependencies: dependencies:
'@sveltejs/kit': registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.0) '@sveltejs/kit': registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.1)
import-meta-resolve: registry.npmjs.org/import-meta-resolve@3.0.0 import-meta-resolve: registry.npmjs.org/import-meta-resolve@3.0.0
dev: true dev: true
@@ -2150,7 +2150,7 @@ packages:
import-meta-resolve: registry.npmjs.org/import-meta-resolve@4.0.0 import-meta-resolve: registry.npmjs.org/import-meta-resolve@4.0.0
dev: true dev: true
registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.0): registry.npmjs.org/@sveltejs/kit@1.22.6(svelte@4.2.1)(vite@4.5.1):
resolution: {integrity: sha512-SDKxI/QpsReCwIn5czjT53fKlPBybbmMk67d317gUqfeORroBAFN1Z6s/x0E1JYi+04i7kKllS+Sz9wVfmUkAQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.6.tgz} resolution: {integrity: sha512-SDKxI/QpsReCwIn5czjT53fKlPBybbmMk67d317gUqfeORroBAFN1Z6s/x0E1JYi+04i7kKllS+Sz9wVfmUkAQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/kit/-/kit-1.22.6.tgz}
id: registry.npmjs.org/@sveltejs/kit/1.22.6 id: registry.npmjs.org/@sveltejs/kit/1.22.6
name: '@sveltejs/kit' name: '@sveltejs/kit'
@@ -2162,7 +2162,7 @@ packages:
svelte: ^3.54.0 || ^4.0.0-next.0 svelte: ^3.54.0 || ^4.0.0-next.0
vite: ^4.0.0 vite: ^4.0.0
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.0) '@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.1)
'@types/cookie': registry.npmjs.org/@types/cookie@0.5.3 '@types/cookie': registry.npmjs.org/@types/cookie@0.5.3
cookie: registry.npmjs.org/cookie@0.5.0 cookie: registry.npmjs.org/cookie@0.5.0
devalue: registry.npmjs.org/devalue@4.3.2 devalue: registry.npmjs.org/devalue@4.3.2
@@ -2175,7 +2175,7 @@ packages:
sirv: registry.npmjs.org/sirv@2.0.3 sirv: registry.npmjs.org/sirv@2.0.3
svelte: registry.npmjs.org/svelte@4.2.1 svelte: registry.npmjs.org/svelte@4.2.1
undici: registry.npmjs.org/undici@5.23.0 undici: registry.npmjs.org/undici@5.23.0
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16) vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -2231,7 +2231,7 @@ packages:
- typescript - typescript
dev: true dev: true
registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6)(svelte@4.2.1)(vite@4.5.0): registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6)(svelte@4.2.1)(vite@4.5.1):
resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz} resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.4.tgz}
id: registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/1.0.4 id: registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/1.0.4
name: '@sveltejs/vite-plugin-svelte-inspector' name: '@sveltejs/vite-plugin-svelte-inspector'
@@ -2242,10 +2242,10 @@ packages:
svelte: ^3.54.0 || ^4.0.0 svelte: ^3.54.0 || ^4.0.0
vite: ^4.0.0 vite: ^4.0.0
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.0) '@sveltejs/vite-plugin-svelte': registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.1)
debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1) debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1)
svelte: registry.npmjs.org/svelte@4.2.1 svelte: registry.npmjs.org/svelte@4.2.1
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16) vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -2268,7 +2268,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.0): registry.npmjs.org/@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.5.1):
resolution: {integrity: sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz} resolution: {integrity: sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.6.tgz}
id: registry.npmjs.org/@sveltejs/vite-plugin-svelte/2.4.6 id: registry.npmjs.org/@sveltejs/vite-plugin-svelte/2.4.6
name: '@sveltejs/vite-plugin-svelte' name: '@sveltejs/vite-plugin-svelte'
@@ -2278,15 +2278,15 @@ packages:
svelte: ^3.54.0 || ^4.0.0 svelte: ^3.54.0 || ^4.0.0
vite: ^4.0.0 vite: ^4.0.0
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte-inspector': registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6)(svelte@4.2.1)(vite@4.5.0) '@sveltejs/vite-plugin-svelte-inspector': registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6)(svelte@4.2.1)(vite@4.5.1)
debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1) debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1)
deepmerge: registry.npmjs.org/deepmerge@4.3.1 deepmerge: registry.npmjs.org/deepmerge@4.3.1
kleur: registry.npmjs.org/kleur@4.1.5 kleur: registry.npmjs.org/kleur@4.1.5
magic-string: registry.npmjs.org/magic-string@0.30.5 magic-string: registry.npmjs.org/magic-string@0.30.5
svelte: registry.npmjs.org/svelte@4.2.1 svelte: registry.npmjs.org/svelte@4.2.1
svelte-hmr: registry.npmjs.org/svelte-hmr@0.15.3(svelte@4.2.1) svelte-hmr: registry.npmjs.org/svelte-hmr@0.15.3(svelte@4.2.1)
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16) vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
vitefu: registry.npmjs.org/vitefu@0.2.5(vite@4.5.0) vitefu: registry.npmjs.org/vitefu@0.2.5(vite@4.5.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -2972,6 +2972,12 @@ packages:
version: 7.5.4 version: 7.5.4
dev: true dev: true
registry.npmjs.org/@types/semver@7.5.6:
resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz}
name: '@types/semver'
version: 7.5.6
dev: true
registry.npmjs.org/@types/sinonjs__fake-timers@8.1.1: registry.npmjs.org/@types/sinonjs__fake-timers@8.1.1:
resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz} resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz}
name: '@types/sinonjs__fake-timers' name: '@types/sinonjs__fake-timers'
@@ -2996,10 +3002,10 @@ packages:
version: 3.0.1 version: 3.0.1
dev: false dev: false
registry.npmjs.org/@types/yauzl@2.10.2: registry.npmjs.org/@types/yauzl@2.10.3:
resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.2.tgz} resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz}
name: '@types/yauzl' name: '@types/yauzl'
version: 2.10.2 version: 2.10.3
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@types/node': registry.npmjs.org/@types/node@18.7.16 '@types/node': registry.npmjs.org/@types/node@18.7.16
@@ -3092,7 +3098,7 @@ packages:
debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1) debug: registry.npmjs.org/debug@4.3.4(supports-color@8.1.1)
eslint: registry.npmjs.org/eslint@8.43.0 eslint: registry.npmjs.org/eslint@8.43.0
graphemer: registry.npmjs.org/graphemer@1.4.0 graphemer: registry.npmjs.org/graphemer@1.4.0
ignore: registry.npmjs.org/ignore@5.2.4 ignore: registry.npmjs.org/ignore@5.3.0
natural-compare: registry.npmjs.org/natural-compare@1.4.0 natural-compare: registry.npmjs.org/natural-compare@1.4.0
semver: registry.npmjs.org/semver@7.5.4 semver: registry.npmjs.org/semver@7.5.4
ts-api-utils: registry.npmjs.org/ts-api-utils@1.0.3(typescript@5.1.3) ts-api-utils: registry.npmjs.org/ts-api-utils@1.0.3(typescript@5.1.3)
@@ -3398,7 +3404,7 @@ packages:
dependencies: dependencies:
'@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0) '@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils@4.4.0(eslint@8.53.0)
'@types/json-schema': registry.npmjs.org/@types/json-schema@7.0.15 '@types/json-schema': registry.npmjs.org/@types/json-schema@7.0.15
'@types/semver': registry.npmjs.org/@types/semver@7.5.4 '@types/semver': registry.npmjs.org/@types/semver@7.5.6
'@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager@6.10.0 '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager@6.10.0
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types@6.10.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types@6.10.0
'@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2) '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree@6.10.0(typescript@5.2.2)
@@ -3420,7 +3426,7 @@ packages:
dependencies: dependencies:
'@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils@4.4.0(eslint@8.43.0) '@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils@4.4.0(eslint@8.43.0)
'@types/json-schema': registry.npmjs.org/@types/json-schema@7.0.15 '@types/json-schema': registry.npmjs.org/@types/json-schema@7.0.15
'@types/semver': registry.npmjs.org/@types/semver@7.5.4 '@types/semver': registry.npmjs.org/@types/semver@7.5.6
'@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager@6.8.0 '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager@6.8.0
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types@6.8.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types@6.8.0
'@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree@6.8.0(typescript@5.1.3) '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree@6.8.0(typescript@5.1.3)
@@ -3498,6 +3504,26 @@ packages:
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16) vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true
registry.npmjs.org/@vitejs/plugin-react@4.1.1(vite@4.5.1):
resolution: {integrity: sha512-Jie2HERK+uh27e+ORXXwEP5h0Y2lS9T2PRGbfebiHGlwzDO0dEnd2aNtOR/qjBlPb1YgxwAONeblL1xqLikLag==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz}
id: registry.npmjs.org/@vitejs/plugin-react/4.1.1
name: '@vitejs/plugin-react'
version: 4.1.1
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.2.0
dependencies:
'@babel/core': registry.npmjs.org/@babel/core@7.23.2
'@babel/plugin-transform-react-jsx-self': registry.npmjs.org/@babel/plugin-transform-react-jsx-self@7.22.5(@babel/core@7.23.2)
'@babel/plugin-transform-react-jsx-source': registry.npmjs.org/@babel/plugin-transform-react-jsx-source@7.22.5(@babel/core@7.23.2)
'@types/babel__core': registry.npmjs.org/@types/babel__core@7.20.4
react-refresh: registry.npmjs.org/react-refresh@0.14.0
vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
transitivePeerDependencies:
- supports-color
dev: false
registry.npmjs.org/acorn-jsx@5.3.2(acorn@8.10.0): registry.npmjs.org/acorn-jsx@5.3.2(acorn@8.10.0):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz} resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz}
@@ -5313,7 +5339,7 @@ packages:
is-weakref: registry.npmjs.org/is-weakref@1.0.2 is-weakref: registry.npmjs.org/is-weakref@1.0.2
object-inspect: registry.npmjs.org/object-inspect@1.13.1 object-inspect: registry.npmjs.org/object-inspect@1.13.1
object-keys: registry.npmjs.org/object-keys@1.1.1 object-keys: registry.npmjs.org/object-keys@1.1.1
object.assign: registry.npmjs.org/object.assign@4.1.4 object.assign: registry.npmjs.org/object.assign@4.1.5
regexp.prototype.flags: registry.npmjs.org/regexp.prototype.flags@1.5.1 regexp.prototype.flags: registry.npmjs.org/regexp.prototype.flags@1.5.1
safe-array-concat: registry.npmjs.org/safe-array-concat@1.0.1 safe-array-concat: registry.npmjs.org/safe-array-concat@1.0.1
safe-regex-test: registry.npmjs.org/safe-regex-test@1.0.0 safe-regex-test: registry.npmjs.org/safe-regex-test@1.0.0
@@ -5985,7 +6011,7 @@ packages:
get-stream: registry.npmjs.org/get-stream@5.2.0 get-stream: registry.npmjs.org/get-stream@5.2.0
yauzl: registry.npmjs.org/yauzl@2.10.0 yauzl: registry.npmjs.org/yauzl@2.10.0
optionalDependencies: optionalDependencies:
'@types/yauzl': registry.npmjs.org/@types/yauzl@2.10.2 '@types/yauzl': registry.npmjs.org/@types/yauzl@2.10.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -6487,7 +6513,7 @@ packages:
array-union: registry.npmjs.org/array-union@2.1.0 array-union: registry.npmjs.org/array-union@2.1.0
dir-glob: registry.npmjs.org/dir-glob@3.0.1 dir-glob: registry.npmjs.org/dir-glob@3.0.1
fast-glob: registry.npmjs.org/fast-glob@3.3.2 fast-glob: registry.npmjs.org/fast-glob@3.3.2
ignore: registry.npmjs.org/ignore@5.2.4 ignore: registry.npmjs.org/ignore@5.3.0
merge2: registry.npmjs.org/merge2@1.4.1 merge2: registry.npmjs.org/merge2@1.4.1
slash: registry.npmjs.org/slash@3.0.0 slash: registry.npmjs.org/slash@3.0.0
dev: true dev: true
@@ -6500,7 +6526,7 @@ packages:
dependencies: dependencies:
dir-glob: registry.npmjs.org/dir-glob@3.0.1 dir-glob: registry.npmjs.org/dir-glob@3.0.1
fast-glob: registry.npmjs.org/fast-glob@3.3.2 fast-glob: registry.npmjs.org/fast-glob@3.3.2
ignore: registry.npmjs.org/ignore@5.2.4 ignore: registry.npmjs.org/ignore@5.3.0
merge2: registry.npmjs.org/merge2@1.4.1 merge2: registry.npmjs.org/merge2@1.4.1
slash: registry.npmjs.org/slash@4.0.0 slash: registry.npmjs.org/slash@4.0.0
dev: true dev: true
@@ -6791,6 +6817,13 @@ packages:
engines: {node: '>= 4'} engines: {node: '>= 4'}
dev: true dev: true
registry.npmjs.org/ignore@5.3.0:
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz}
name: ignore
version: 5.3.0
engines: {node: '>= 4'}
dev: true
registry.npmjs.org/immediate@3.0.6: registry.npmjs.org/immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz} resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz}
name: immediate name: immediate
@@ -7431,7 +7464,7 @@ packages:
dependencies: dependencies:
array-includes: registry.npmjs.org/array-includes@3.1.7 array-includes: registry.npmjs.org/array-includes@3.1.7
array.prototype.flat: registry.npmjs.org/array.prototype.flat@1.3.2 array.prototype.flat: registry.npmjs.org/array.prototype.flat@1.3.2
object.assign: registry.npmjs.org/object.assign@4.1.4 object.assign: registry.npmjs.org/object.assign@4.1.5
object.values: registry.npmjs.org/object.values@1.1.7 object.values: registry.npmjs.org/object.values@1.1.7
dev: true dev: true
@@ -8560,10 +8593,10 @@ packages:
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true dev: true
registry.npmjs.org/object.assign@4.1.4: registry.npmjs.org/object.assign@4.1.5:
resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz} resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz}
name: object.assign name: object.assign
version: 4.1.4 version: 4.1.5
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dependencies: dependencies:
call-bind: registry.npmjs.org/call-bind@1.0.5 call-bind: registry.npmjs.org/call-bind@1.0.5
@@ -9487,6 +9520,16 @@ packages:
picocolors: registry.npmjs.org/picocolors@1.0.0 picocolors: registry.npmjs.org/picocolors@1.0.0
source-map-js: registry.npmjs.org/source-map-js@1.0.2 source-map-js: registry.npmjs.org/source-map-js@1.0.2
registry.npmjs.org/postcss@8.4.32:
resolution: {integrity: sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz}
name: postcss
version: 8.4.32
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: registry.npmjs.org/nanoid@3.3.7
picocolors: registry.npmjs.org/picocolors@1.0.0
source-map-js: registry.npmjs.org/source-map-js@1.0.2
registry.npmjs.org/prebuild-install@7.1.1: registry.npmjs.org/prebuild-install@7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz} resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz}
name: prebuild-install name: prebuild-install
@@ -11206,7 +11249,7 @@ packages:
typescript: registry.npmjs.org/typescript@5.1.3 typescript: registry.npmjs.org/typescript@5.1.3
dev: true dev: true
registry.npmjs.org/svelte2tsx@0.6.23(svelte@4.2.1)(typescript@5.2.2): registry.npmjs.org/svelte2tsx@0.6.23(svelte@4.2.1)(typescript@5.3.3):
resolution: {integrity: sha512-3bwd1PuWUA3oEXy8+85zrLDnmJOsVpShpKVAehGWeYsz/66zMihTpRpUN97VVAKTZbO5tP4wnchHUXYs0zOwdw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.23.tgz} resolution: {integrity: sha512-3bwd1PuWUA3oEXy8+85zrLDnmJOsVpShpKVAehGWeYsz/66zMihTpRpUN97VVAKTZbO5tP4wnchHUXYs0zOwdw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.6.23.tgz}
id: registry.npmjs.org/svelte2tsx/0.6.23 id: registry.npmjs.org/svelte2tsx/0.6.23
name: svelte2tsx name: svelte2tsx
@@ -11218,7 +11261,7 @@ packages:
dedent-js: registry.npmjs.org/dedent-js@1.0.1 dedent-js: registry.npmjs.org/dedent-js@1.0.1
pascal-case: registry.npmjs.org/pascal-case@3.1.2 pascal-case: registry.npmjs.org/pascal-case@3.1.2
svelte: registry.npmjs.org/svelte@4.2.1 svelte: registry.npmjs.org/svelte@4.2.1
typescript: registry.npmjs.org/typescript@5.2.2 typescript: registry.npmjs.org/typescript@5.3.3
dev: false dev: false
registry.npmjs.org/svelte@4.2.1: registry.npmjs.org/svelte@4.2.1:
@@ -11755,6 +11798,14 @@ packages:
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
registry.npmjs.org/typescript@5.3.3:
resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz}
name: typescript
version: 5.3.3
engines: {node: '>=14.17'}
hasBin: true
dev: false
registry.npmjs.org/ultrahtml@1.5.2: registry.npmjs.org/ultrahtml@1.5.2:
resolution: {integrity: sha512-qh4mBffhlkiXwDAOxvSGxhL0QEQsTbnP9BozOK3OYPEGvPvdWzvAUaXNtUSMdNsKDtuyjEbyVUPFZ52SSLhLqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.2.tgz} resolution: {integrity: sha512-qh4mBffhlkiXwDAOxvSGxhL0QEQsTbnP9BozOK3OYPEGvPvdWzvAUaXNtUSMdNsKDtuyjEbyVUPFZ52SSLhLqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.2.tgz}
name: ultrahtml name: ultrahtml
@@ -12090,6 +12141,44 @@ packages:
optionalDependencies: optionalDependencies:
fsevents: registry.npmjs.org/fsevents@2.3.3 fsevents: registry.npmjs.org/fsevents@2.3.3
registry.npmjs.org/vite@4.5.1(@types/node@18.7.16):
resolution: {integrity: sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vite/-/vite-4.5.1.tgz}
id: registry.npmjs.org/vite/4.5.1
name: vite
version: 4.5.1
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
less: '*'
lightningcss: ^1.21.0
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
'@types/node': registry.npmjs.org/@types/node@18.7.16
esbuild: registry.npmjs.org/esbuild@0.18.20
postcss: registry.npmjs.org/postcss@8.4.32
rollup: registry.npmjs.org/rollup@3.29.4
optionalDependencies:
fsevents: registry.npmjs.org/fsevents@2.3.3
registry.npmjs.org/vitefu@0.2.5(vite@4.5.0): registry.npmjs.org/vitefu@0.2.5(vite@4.5.0):
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz} resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz}
id: registry.npmjs.org/vitefu/0.2.5 id: registry.npmjs.org/vitefu/0.2.5
@@ -12103,6 +12192,19 @@ packages:
dependencies: dependencies:
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16) vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16)
registry.npmjs.org/vitefu@0.2.5(vite@4.5.1):
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz}
id: registry.npmjs.org/vitefu/0.2.5
name: vitefu
version: 0.2.5
peerDependencies:
vite: ^3.0.0 || ^4.0.0 || ^5.0.0
peerDependenciesMeta:
vite:
optional: true
dependencies:
vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
registry.npmjs.org/vscode-oniguruma@1.7.0: registry.npmjs.org/vscode-oniguruma@1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz} resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz}
name: vscode-oniguruma name: vscode-oniguruma

Some files were not shown because too many files have changed in this diff Show More