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 UseOnSelectionChange from '../examples/UseOnSelectionChange';
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 {
name: string;
@@ -261,7 +263,7 @@ const routes: IRoute[] = [
{
name: 'useNodesInitialized',
path: 'use-nodes-initialized',
component: useNodesInitialized,
component: UseNodesInitialized,
},
{
name: 'useOnSelectionChange',
@@ -273,6 +275,16 @@ const routes: IRoute[] = [
path: 'usereactflow',
component: UseReactFlow,
},
{
name: 'useHandleConnections',
path: 'usehandleconnections',
component: UseHandleConnections,
},
{
name: 'useNodesData',
path: 'usenodesdata',
component: UseNodesData,
},
{
name: 'useUpdateNodeInternals',
path: 'useupdatenodeinternals',
@@ -15,6 +15,8 @@ import {
Position,
} from '@xyflow/react';
import './style.css';
const nodeDefaults = {
sourcePosition: Position.Right,
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';
const targetHandleStyle: CSSProperties = { background: '#555' };
@@ -1,5 +1,5 @@
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';
@@ -13,6 +13,7 @@ const initialEdges: Edge[] = [{ id: 'e1-2', source: '1', target: '2' }];
const UpdateNode = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const { updateNode } = useReactFlow();
const [nodeName, setNodeName] = useState<string>('Node 1');
const [nodeBg, setNodeBg] = useState<string>('#eee');
@@ -80,9 +81,19 @@ const UpdateNode = () => {
<label>hidden:</label>
<input type="checkbox" checked={nodeHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} />
</div>
<button
onClick={() => updateNode('1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }))}
>
update position
</button>
</div>
</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 = [
'add-node-on-drop',
'colormode',
'color-mode',
'custom-connection-line',
'customnode',
'dagre',
'drag-n-drop',
'edges',
'figma',
'handle-connect',
'interaction',
'intersections',
'node-toolbar',
@@ -18,6 +19,7 @@
'stress',
'subflows',
'two-way-viewport',
'usenodesdata',
'usesvelteflow',
'useupdatenodeinternals',
'validation'
@@ -1,6 +1,12 @@
<script lang="ts">
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';
@@ -16,16 +22,18 @@
const nodes = writable<Node[]>(initialNodes);
const edges = writable<Edge[]>([]);
let connectingNodeId: string = '0';
let connectingNodeId: string | null = '0';
let rect: DOMRectReadOnly;
let id = 1;
const getId = () => `${id++}`;
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
const targetIsPane = event.target?.classList.contains('svelte-flow__pane');
const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('svelte-flow__pane');
if (targetIsPane) {
const id = getId();
const position = {
@@ -58,7 +66,7 @@
$nodes = $nodes;
$edges = $edges;
}
}
};
</script>
<svelte:window />
@@ -69,11 +77,11 @@
{edges}
fitView
fitViewOptions={{ padding: 2 }}
on:connectstart={({ detail: { nodeId } }) => {
onconnectstart={(_, { nodeId }) => {
// Memorize the nodeId you start draggin a connection line from a node
connectingNodeId = nodeId;
}}
on:connectend={handleConnectEnd}
onconnectend={handleConnectEnd}
/>
</div>
@@ -85,9 +85,9 @@
{nodes}
{edges}
{nodeTypes}
style="--background-color: {$bgColor}"
style="--xy-background-color: {$bgColor}"
fitView
on:connect={onConnect}
onconnect={onConnect}
>
<Controls />
<Background variant={BackgroundVariant.Dots} />
@@ -10,7 +10,7 @@
</script>
<div class="custom">
<Handle type="target" position={Position.Left} on:connect />
<Handle type="target" position={Position.Left} />
<div>
Custom Color Picker Node: <strong>{$colorStore}</strong>
</div>
@@ -20,14 +20,8 @@
on:input={(evt) => colorStore.set(evt.currentTarget.value)}
value={$colorStore}
/>
<Handle type="source" position={Position.Right} id="a" style="top: 20px;" on:connect />
<Handle
type="source"
position={Position.Right}
id="b"
style="top: auto; bottom: 10px;"
on:connect
/>
<Handle type="source" position={Position.Right} id="a" style="top: 20px;" />
<Handle type="source" position={Position.Right} id="b" style="top: auto; bottom: 10px;" />
</div>
<style>
@@ -6,10 +6,13 @@
Background,
BackgroundVariant,
MiniMap,
MarkerType
MarkerType,
type Connection
} from '@xyflow/svelte';
import '@xyflow/svelte/dist/style.css';
import ButtonEdge from './ButtonEdge.svelte';
import CustomBezierEdge from './CustomBezierEdge.svelte';
const nodes = writable([
{
@@ -110,13 +113,14 @@
id: 'e5-8',
source: '5',
target: '8',
data: { text: 'custom edge' }
type: 'button'
},
{
id: 'e5-9',
source: '5',
target: '9',
data: { text: 'custom edge 2' }
type: 'customBezier',
label: 'custom bezier'
},
{
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>
<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 />
<Background variant={BackgroundVariant.Dots} />
<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 Node,
type Edge,
ConnectionMode
ConnectionMode,
useSvelteFlow
} from '@xyflow/svelte';
import CustomNode from './CustomNode.svelte';
@@ -150,9 +151,9 @@
on:nodemouseenter={(event) => console.log('on node enter', event)}
on:nodemouseleave={(event) => console.log('on node leave', event)}
on:edgeclick={(event) => console.log('edge click', event)}
on:connectstart={(event) => console.log('on connect start', event)}
on:connect={(event) => console.log('on connect', event)}
on:connectend={(event) => console.log('on connect end', event)}
onconnectstart={(event) => console.log('on connect start', event)}
onconnect={(event) => console.log('on connect', event)}
onconnectend={(event) => console.log('on connect end', event)}
on:paneclick={(event) => console.log('on pane click', event)}
on:panecontextmenu={(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>
<Handle type="target" position={Position.Top} on:connect />
<Handle type="target" position={Position.Top} />
<button on:click={onClick}>add handle</button>
{#each Array.from({ length: handleCount }) as handle, i}
<Handle
type="source"
position={Position.Bottom}
id={`${i}`}
style={`left: ${i * 10}px;`}
on:connect
/>
<Handle type="source" position={Position.Bottom} id={`${i}`} style={`left: ${i * 10}px;`} />
{/each}
@@ -6,7 +6,9 @@
Background,
BackgroundVariant,
MiniMap,
type NodeTypes
type NodeTypes,
useSvelteFlow,
Panel
} from '@xyflow/svelte';
import CustomNode from './CustomNode.svelte';
@@ -50,6 +52,12 @@
target: '3'
}
]);
const { updateNode } = useSvelteFlow();
const updateNodePosition = () => {
updateNode('1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));
};
</script>
<main>
@@ -57,6 +65,8 @@
<Controls />
<Background variant={BackgroundVariant.Dots} />
<MiniMap />
<Panel><button on:click={updateNodePosition}>update node</button></Panel>
</SvelteFlow>
</main>
@@ -55,8 +55,8 @@ function Background({
{
...style,
...containerStyle,
'--background-color-props': bgColor,
'--background-pattern-color-props': color,
'--xy-background-color-props': bgColor,
'--xy-background-pattern-color-props': color,
} as CSSProperties
}
ref={ref}
@@ -129,10 +129,10 @@ function MiniMap({
style={
{
...style,
'--minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
'--minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
'--minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
'--minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
'--xy-minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
'--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
'--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
'--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
} as CSSProperties
}
className={cc(['react-flow__minimap', className])}
@@ -4,56 +4,67 @@ import { Position, getBezierPath } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { BezierEdgeProps } from '../../types';
const BezierEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: BezierEdgeProps) => {
const [path, labelX, labelY] = getBezierPath({
function createBezierEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: pathOptions?.curvature,
});
sourcePosition = Position.Bottom,
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 (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const BezierEdge = createBezierEdge({ isInternal: false });
const BezierEdgeInternal = createBezierEdge({ isInternal: true });
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 BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types';
import type { SimpleBezierEdgeProps } from '../../types';
export interface GetSimpleBezierPathParams {
sourceX: number;
@@ -71,54 +71,65 @@ export function getSimpleBezierPath({
];
}
const SimpleBezierEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: EdgeProps) => {
const [path, labelX, labelY] = getSimpleBezierPath({
function createSimpleBezierEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
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 (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const SimpleBezierEdge = createSimpleBezierEdge({ isInternal: false });
const SimpleBezierEdgeInternal = createSimpleBezierEdge({ isInternal: true });
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 type { SmoothStepEdgeProps } from '../../types';
const SmoothStepEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: SmoothStepEdgeProps) => {
const [path, labelX, labelY] = getSmoothStepPath({
function createSmoothStepEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset,
});
label,
labelStyle,
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 (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const SmoothStepEdge = createSmoothStepEdge({ isInternal: false });
const SmoothStepEdgeInternal = createSmoothStepEdge({ isInternal: true });
SmoothStepEdge.displayName = 'SmoothStepEdge';
SmoothStepEdgeInternal.displayName = 'SmoothStepEdgeInternal';
export default SmoothStepEdge;
export { SmoothStepEdge, SmoothStepEdgeInternal };
@@ -1,15 +1,30 @@
import { memo, useMemo } from 'react';
import SmoothStepEdge from './SmoothStepEdge';
import type { SmoothStepEdgeProps } from '../../types';
import { SmoothStepEdge } from './SmoothStepEdge';
import type { StepEdgeProps } from '../../types';
const StepEdge = memo((props: SmoothStepEdgeProps) => (
<SmoothStepEdge
{...props}
pathOptions={useMemo(() => ({ borderRadius: 0, offset: props.pathOptions?.offset }), [props.pathOptions?.offset])}
/>
));
function createStepEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(({ id, ...props }: StepEdgeProps) => {
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';
StepEdgeInternal.displayName = 'StepEdgeInternal';
export default StepEdge;
export { StepEdge, StepEdgeInternal };
@@ -2,47 +2,58 @@ import { memo } from 'react';
import { getStraightPath } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types';
import type { StraightEdgeProps } from '../../types';
const StraightEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: EdgeProps) => {
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
function createStraightEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: StraightEdgeProps) => {
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
return (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const StraightEdge = createStraightEdge({ isInternal: false });
const StraightEdgeInternal = createStraightEdge({ isInternal: true });
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';
export { default as SmoothStepEdge } from './SmoothStepEdge';
export { default as StepEdge } from './StepEdge';
export { default as StraightEdge } from './StraightEdge';
export { default as BezierEdge } from './BezierEdge';
// 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
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,
});
if (isValid) {
if (isValid && connection) {
onConnectExtended(connection);
}
@@ -1,6 +1,12 @@
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 type { EdgeProps, EdgeTypes, EdgeTypesWrapped } from '../../types';
@@ -8,18 +14,18 @@ export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypesWrapped;
export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypesWrapped {
const standardTypes: EdgeTypesWrapped = {
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType<EdgeProps>),
smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType<EdgeProps>),
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdge) as ComponentType<EdgeProps>),
default: wrapEdge((edgeTypes.default || BezierEdgeInternal) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdgeInternal) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdgeInternal) as ComponentType<EdgeProps>),
smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdgeInternal) as ComponentType<EdgeProps>),
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdgeInternal) as ComponentType<EdgeProps>),
};
const wrappedTypes = {} as EdgeTypesWrapped;
const specialTypes: EdgeTypesWrapped = Object.keys(edgeTypes)
.filter((k) => !['default', 'bezier'].includes(k))
.reduce((res, key) => {
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeProps>);
res[key] = wrapEdge((edgeTypes[key] || BezierEdgeInternal) as ComponentType<EdgeProps>);
return res;
}, wrappedTypes);
@@ -12,7 +12,13 @@ import {
} from '@xyflow/system';
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 InputNode from '../../components/Nodes/InputNode';
import OutputNode from '../../components/Nodes/OutputNode';
@@ -33,11 +39,11 @@ const defaultNodeTypes: NodeTypes = {
};
const defaultEdgeTypes: EdgeTypes = {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge,
smoothstep: SmoothStepEdge,
simplebezier: SimpleBezierEdge,
default: BezierEdgeInternal,
straight: StraightEdgeInternal,
step: StepEdgeInternal,
smoothstep: SmoothStepEdgeInternal,
simplebezier: SimpleBezierEdgeInternal,
};
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';
import useViewportHelper from './useViewportHelper';
import { useStoreApi } from '../hooks/useStore';
import { useStoreApi } from './useStore';
import type {
ReactFlowInstance,
Instance,
@@ -24,6 +24,7 @@ import type {
Node,
Edge,
} from '../types';
import { isNode } from '../utils';
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
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);
}, []);
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 {
...viewportHelper,
@@ -289,6 +320,8 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
getConnectedEdges,
getIncomers,
getOutgoers,
updateNode,
updateNodeData,
};
}, [
viewportHelper,
+8 -6
View File
@@ -1,11 +1,11 @@
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 StraightEdge } from './components/Edges/StraightEdge';
export { default as StepEdge } from './components/Edges/StepEdge';
export { default as BezierEdge } from './components/Edges/BezierEdge';
export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
export { default as SmoothStepEdge } from './components/Edges/SmoothStepEdge';
export { StraightEdge } from './components/Edges/StraightEdge';
export { StepEdge } from './components/Edges/StepEdge';
export { BezierEdge } from './components/Edges/BezierEdge';
export { SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
export { SmoothStepEdge } from './components/Edges/SmoothStepEdge';
export { default as BaseEdge } from './components/Edges/BaseEdge';
export { default as ReactFlowProvider } from './components/ReactFlowProvider';
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 useOnSelectionChange, type UseOnSelectionChangeOptions } from './hooks/useOnSelectionChange';
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 { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes';
+8 -2
View File
@@ -7,6 +7,7 @@ import {
panBy as panBySystem,
Dimensions,
updateNodeDimensions as updateNodeDimensionsSystem,
updateConnectionLookup,
} from '@xyflow/system';
import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -49,8 +50,12 @@ const createRFStore = ({
set({ nodes: nextNodes });
},
setEdges: (edges: Edge[]) => {
const { defaultEdgeOptions = {} } = get();
set({ edges: edges.map((e) => ({ ...defaultEdgeOptions, ...e })) });
const { defaultEdgeOptions = {}, connectionLookup } = get();
const nextEdges = edges.map((e) => ({ ...defaultEdgeOptions, ...e }));
updateConnectionLookup(connectionLookup, nextEdges);
set({ edges: nextEdges });
},
// when the user works with an uncontrolled flow,
// we set a flag `hasDefaultNodes` / `hasDefaultEdges`
@@ -326,6 +331,7 @@ const createRFStore = ({
set(currentConnection);
},
reset: () => {
// @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
+4 -1
View File
@@ -5,6 +5,7 @@ import {
getNodesBounds,
getViewportForBounds,
Transform,
updateConnectionLookup,
} from '@xyflow/system';
import type { Edge, Node, ReactFlowStore } from '../types';
@@ -22,7 +23,8 @@ const getInitialState = ({
height?: number;
fitView?: boolean;
} = {}): 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 });
let transform: Transform = [0, 0, 1];
@@ -42,6 +44,7 @@ const getInitialState = ({
nodes: nextNodes,
nodeLookup,
edges: edges,
connectionLookup,
onNodesChange: null,
onEdgesChange: null,
hasDefaultNodes: false,
+20 -3
View File
@@ -13,6 +13,8 @@ import type {
HandleElement,
ConnectionStatus,
EdgePosition,
Optional,
StepPathOptions,
} from '@xyflow/system';
import { Node } from '.';
@@ -46,7 +48,12 @@ type BezierEdgeType<T> = DefaultEdge<T> & {
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;
@@ -100,14 +107,24 @@ export type BaseEdgeProps = Pick<EdgeProps, 'style' | 'markerStart' | 'markerEnd
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;
};
export type BezierEdgeProps<T = any> = EdgeProps<T> & {
export type BezierEdgeProps<T = any> = EdgeComponentProps<T> & {
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 ConnectionLineComponentProps = {
+13
View File
@@ -45,6 +45,17 @@ export namespace Instance {
export type getConnectedEdges = (id: string | (Node | { id: Node['id'] })[]) => Edge[];
export type getIncomers = (node: string | Node | { id: Node['id'] }) => Node[];
export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[];
export type UpdateNode = (
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> = {
@@ -60,5 +71,7 @@ export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
deleteElements: Instance.DeleteElements;
getIntersectingNodes: Instance.GetIntersectingNodes<NodeData>;
isNodeIntersecting: Instance.IsNodeIntersecting<NodeData>;
updateNode: Instance.UpdateNode;
updateNodeData: Instance.UpdateNodeData;
viewportInitialized: boolean;
} & Omit<ViewportHelperFunctions, 'initialized'>;
+3
View File
@@ -24,6 +24,7 @@ import {
type OnMoveEnd,
type IsValidConnection,
type UpdateConnection,
Connection,
} from '@xyflow/system';
import type {
@@ -49,6 +50,8 @@ export type ReactFlowStore = {
nodes: Node[];
nodeLookup: Map<string, Node>;
edges: Edge[];
connectionLookup: Map<string, Map<string, Connection>>;
onNodesChange: OnNodesChange | null;
onEdgesChange: OnEdgesChange | null;
hasDefaultNodes: boolean;
+2 -2
View File
@@ -10,8 +10,8 @@ import {
import type { Edge, Node } from '../types';
export const isNode = isNodeBase<Node, Edge>;
export const isEdge = isEdgeBase<Node, Edge>;
export const isNode = isNodeBase<Node>;
export const isEdge = isEdgeBase<Edge>;
export const getOutgoers = getOutgoersBase<Node, Edge>;
export const getIncomers = getIncomersBase<Node, 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
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 `on:selectionclick` and `on:selectioncontextmenu` event handlers
- add `ondelete({ nodes, edges })` handler
- add `zoomActivationKey` prop
- add `zoomActivationKey` prop
- add `width` and `height` prop to custom `NodeProps` type
- add `colorMode` prop ('light' | 'dark' | 'system')
- ⚠️ 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
- 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 `flowToScreenCoordinate` to `flowToScreenPosition`
- ⚠️ 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
- add `connectionLine` slot for rendering a custom connection line
- add `connectionLine` slot for rendering a custom connection line
- add `connectionLineStyle` and `connectionLineContainerStyle` props
- add `useConnection` hook
- 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
- add `nodesDraggable` prop
- add `nodesDraggable` prop
- minimap: add default background
## 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
- fix wrongly displayed connectionline
- fix wrongly displayed connectionline
## 0.0.14
@@ -152,14 +177,14 @@ this version is broken because of a wrong path in the package.json
- 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:
- pass `nodes` and `edges` as writables
- draggable, selectable and deletable nodes
- pass `nodes` and `edges` as writables
- draggable, selectable and deletable nodes
- support for custom `nodeTypes` and `edgeTypes`
- basic viewport settings like `fitView`, `minZoom` and `maxZoom`
- additional components: `<MiniMap />`, `<Controls />` & `<Background />`
+2 -2
View File
@@ -1,6 +1,6 @@
{
"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.",
"keywords": [
"svelte",
@@ -41,7 +41,7 @@
"access": "public"
},
"dependencies": {
"@svelte-put/shortcut": "^3.0.0",
"@svelte-put/shortcut": "^3.1.0",
"@xyflow/system": "workspace:*",
"classcat": "^5.0.4"
},
@@ -6,7 +6,7 @@
import { errorMessages, getMarkerId } from '@xyflow/system';
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 { get } from 'svelte/store';
@@ -57,7 +57,7 @@
edgecontextmenu: { edge: Edge; event: MouseEvent };
}>();
$: edgeComponent = $edgeTypes[type!] || BezierEdge;
$: edgeComponent = $edgeTypes[type!] || BezierEdgeInternal;
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
@@ -1,17 +1,18 @@
<script lang="ts">
import { getContext, createEventDispatcher } from 'svelte';
import { getContext } from 'svelte';
import type { Writable } from 'svelte/store';
import cc from 'classcat';
import {
Position,
XYHandle,
isMouseEvent,
type Connection,
type HandleType
areConnectionMapsEqual,
handleConnectionChange
} from '@xyflow/system';
import { useStore } from '$lib/store';
import type { HandleComponentProps } from '$lib/types';
import type { Writable } from 'svelte/store';
type $$Props = HandleComponentProps;
@@ -20,6 +21,8 @@
export let position: $$Props['position'] = Position.Top;
export let style: $$Props['style'] = 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 isConnectableEnd: $$Props['isConnectableEnd'] = undefined;
@@ -32,18 +35,6 @@
$: handleConnectable = isConnectable !== undefined ? isConnectable : $connectable;
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 {
@@ -55,10 +46,16 @@
isValidConnection,
lib,
addEdge,
onedgecreate,
panBy,
cancelConnection,
updateConnection,
autoPanOnConnect
autoPanOnConnect,
edges,
connectionLookup,
onconnect: onConnectAction,
onconnectstart: onConnectStartAction,
onconnectend: onConnectEndAction
} = store;
function onPointerDown(event: MouseEvent | TouchEvent) {
@@ -80,28 +77,50 @@
cancelConnection,
panBy,
onConnect: (connection) => {
addEdge(connection);
const edge = $onedgecreate ? $onedgecreate(connection) : connection;
// @todo: should we change/ improve the stuff we are passing here?
// instead of source/target we could pass fromNodeId, fromHandleId, etc
dispatch('connect', { connection });
if (!edge) {
return;
}
addEdge(edge);
$onConnectAction?.(connection);
},
onConnectStart: (event, startParams) => {
dispatch('connectstart', {
event,
$onConnectStartAction?.(event, {
nodeId: startParams.nodeId,
handleId: startParams.handleId,
handleType: startParams.handleType
});
},
onConnectEnd: (event) => {
dispatch('connectend', { event });
$onConnectEndAction?.(event);
},
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
</script>
@@ -1,10 +1,10 @@
<script lang="ts">
import { shortcut, type ShortcutModifierDefinition } from '@svelte-put/shortcut';
import { isInputDOMNode, isMacOs } from '@xyflow/system';
import { useStore } from '$lib/store';
import type { KeyHandlerProps } from './types';
import type { KeyDefinition, KeyDefinitionObject } from '$lib/types';
import { isMacOs } from '@xyflow/system';
type $$Props = KeyHandlerProps;
@@ -23,7 +23,7 @@
} = useStore();
function isKeyObject(key?: KeyDefinition | null): key is KeyDefinitionObject {
return typeof key === 'object';
return key !== null && typeof key === 'object';
}
function getModifier(key?: KeyDefinition | null): ShortcutModifierDefinition {
@@ -71,16 +71,19 @@
trigger: [
{
...selectionKeyDefinition,
callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(true)
enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(true)
}
],
type: 'keydown'
}}
use:shortcut={{
trigger: [
{
...selectionKeyDefinition,
callback: () => selectionKeyDefinition.key && selectionKeyPressed.set(false)
enabled: selectionKeyDefinition.key !== null,
callback: () => selectionKeyPressed.set(false)
}
],
type: 'keyup'
@@ -89,7 +92,8 @@
trigger: [
{
...multiSelectionKeyDefinition,
callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(true)
enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(true)
}
],
type: 'keydown'
@@ -98,7 +102,8 @@
trigger: [
{
...multiSelectionKeyDefinition,
callback: () => multiSelectionKeyDefinition.key && multiselectionKeyPressed.set(false)
enabled: multiSelectionKeyDefinition.key !== null,
callback: () => multiselectionKeyPressed.set(false)
}
],
type: 'keyup'
@@ -107,7 +112,8 @@
trigger: [
{
...deleteKeyDefinition,
callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(true)
enabled: deleteKeyDefinition.key !== null,
callback: (detail) => !isInputDOMNode(detail.originalEvent) && deleteKeyPressed.set(true)
}
],
type: 'keydown'
@@ -116,7 +122,8 @@
trigger: [
{
...deleteKeyDefinition,
callback: () => deleteKeyDefinition.key && deleteKeyPressed.set(false)
enabled: deleteKeyDefinition.key !== null,
callback: () => deleteKeyPressed.set(false)
}
],
type: 'keyup'
@@ -125,7 +132,8 @@
trigger: [
{
...panActivationKeyDefinition,
callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(true)
enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(true)
}
],
type: 'keydown'
@@ -134,7 +142,8 @@
trigger: [
{
...panActivationKeyDefinition,
callback: () => panActivationKeyDefinition.key && panActivationKeyPressed.set(false)
enabled: panActivationKeyDefinition.key !== null,
callback: () => panActivationKeyPressed.set(false)
}
],
type: 'keyup'
@@ -143,7 +152,8 @@
trigger: [
{
...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(true)
enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(true)
}
],
type: 'keydown'
@@ -152,7 +162,8 @@
trigger: [
{
...zoomActivationKeyDefinition,
callback: () => zoomActivationKeyDefinition.key && zoomActivationKeyPressed.set(false)
enabled: zoomActivationKeyDefinition.key !== null,
callback: () => zoomActivationKeyPressed.set(false)
}
],
type: 'keyup'
@@ -194,9 +194,6 @@
positionAbsolute={{ x: positionX, y: positionY }}
{width}
{height}
on:connectstart
on:connect
on:connectend
/>
</div>
{/if}
@@ -1,30 +1,48 @@
<script lang="ts">
import { getBezierPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import type { BezierEdgeProps } from '$lib/types';
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({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
sourcePosition: $$props.sourcePosition,
targetPosition: $$props.targetPosition
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
curvature: pathOptions?.curvature
});
</script>
<BaseEdge
{id}
{path}
{labelX}
{labelY}
id={$$props.id}
label={$$props.label}
labelStyle={$$props.labelStyle}
markerStart={$$props.markerStart}
markerEnd={$$props.markerEnd}
interactionWidth={$$props.interactionWidth}
style={$$props.style}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{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">
import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import type { SmoothStepEdgeProps } from '$lib/types';
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({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
sourcePosition: $$props.sourcePosition,
targetPosition: $$props.targetPosition
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset
});
</script>
<BaseEdge
{id}
{path}
{labelX}
{labelY}
id={$$props.id}
label={$$props.label}
labelStyle={$$props.labelStyle}
markerStart={$$props.markerStart}
markerEnd={$$props.markerEnd}
interactionWidth={$$props.interactionWidth}
style={$$props.style}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{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">
import { getSmoothStepPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import type { StepEdgeProps } from '$lib/types';
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({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY,
sourcePosition: $$props.sourcePosition,
targetPosition: $$props.targetPosition,
borderRadius: 0
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
borderRadius: 0,
offset: pathOptions?.offset
});
</script>
<BaseEdge
{id}
{path}
{labelX}
{labelY}
id={$$props.id}
label={$$props.label}
labelStyle={$$props.labelStyle}
markerStart={$$props.markerStart}
markerEnd={$$props.markerEnd}
interactionWidth={$$props.interactionWidth}
style={$$props.style}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{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">
import { getStraightPath } from '@xyflow/system';
import type { EdgeProps } from '$lib/types';
import type { StraightEdgeProps } from '$lib/types';
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({
sourceX: $$props.sourceX,
sourceY: $$props.sourceY,
targetX: $$props.targetX,
targetY: $$props.targetY
sourceX,
sourceY,
targetX,
targetY
});
</script>
<BaseEdge
{id}
{path}
{labelX}
{labelY}
id={$$props.id}
label={$$props.label}
labelStyle={$$props.labelStyle}
markerStart={$$props.markerStart}
markerEnd={$$props.markerEnd}
interactionWidth={$$props.interactionWidth}
style={$$props.style}
{label}
{labelStyle}
{markerStart}
{markerEnd}
{interactionWidth}
{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 StraightEdge } from './StraightEdge.svelte';
export { default as BezierEdgeInternal } from './BezierEdgeInternal.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 StepEdgeInternal } from './StepEdgeInternal.svelte';
@@ -37,6 +37,6 @@
isConnectable;
</script>
<Handle type="target" position={targetPosition} on:connectstart on:connect on:connectend />
<Handle type="target" position={targetPosition} />
{data?.label}
<Handle type="source" position={sourcePosition} on:connectstart on:connect on:connectend />
<Handle type="source" position={sourcePosition} />
@@ -39,4 +39,4 @@
</script>
{data?.label}
<Handle type="source" position={sourcePosition} on:connectstart on:connect on:connectend />
<Handle type="source" position={sourcePosition} />
@@ -36,4 +36,4 @@
</script>
{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:nodemousemove
on:nodemouseleave
on:connectstart
on:connect
on:connectend
on:nodedrag
on:nodedragstart
on:nodedragstop
@@ -71,12 +71,16 @@
export let autoPanOnNodeDrag: $$Props['autoPanOnNodeDrag'] = true;
export let onerror: $$Props['onerror'] = undefined;
export let ondelete: $$Props['ondelete'] = undefined;
export let onedgecreate: $$Props['onedgecreate'] = undefined;
export let attributionPosition: $$Props['attributionPosition'] = undefined;
export let proOptions: $$Props['proOptions'] = undefined;
export let defaultEdgeOptions: $$Props['defaultEdgeOptions'] = undefined;
export let width: $$Props['width'] = undefined;
export let height: $$Props['height'] = undefined;
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';
@@ -149,8 +153,12 @@
autoPanOnNodeDrag,
onerror,
ondelete,
onedgecreate,
connectionMode,
nodeDragThreshold
nodeDragThreshold,
onconnect,
onconnectstart,
onconnectend
};
updateStoreByKeys(store, updatableProps);
@@ -215,9 +223,6 @@
on:nodemouseenter
on:nodemousemove
on:nodemouseleave
on:connectstart
on:connect
on:connectend
on:nodedragstart
on:nodedrag
on:nodedragstop
@@ -15,7 +15,10 @@ import type {
ConnectionMode,
PanelPosition,
ProOptions,
ColorMode
ColorMode,
OnConnect,
OnConnectStart,
OnConnectEnd
} from '@xyflow/system';
import type {
@@ -26,7 +29,8 @@ import type {
EdgeTypes,
DefaultEdgeOptions,
FitViewOptions,
OnDelete
OnDelete,
OnEdgeCreate
} from '$lib/types';
import type { Writable } from 'svelte/store';
@@ -89,4 +93,10 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
onMoveEnd?: OnMoveEnd;
onerror?: OnError;
ondelete?: OnDelete;
onedgecreate?: OnEdgeCreate;
onconnect?: OnConnect;
onconnectstart?: OnConnectStart;
onconnectend?: OnConnectEnd;
};
@@ -64,7 +64,11 @@ export type UpdatableStoreProps = {
connectionMode?: UnwrapWritable<SvelteFlowStore['connectionMode']>;
onerror?: UnwrapWritable<SvelteFlowStore['onerror']>;
ondelete?: UnwrapWritable<SvelteFlowStore['ondelete']>;
onedgecreate?: UnwrapWritable<SvelteFlowStore['onedgecreate']>;
nodeDragThreshold?: UnwrapWritable<SvelteFlowStore['nodeDragThreshold']>;
onconnect?: UnwrapWritable<SvelteFlowStore['onconnect']>;
onconnectstart?: UnwrapWritable<SvelteFlowStore['onconnectstart']>;
onconnectend?: UnwrapWritable<SvelteFlowStore['onconnectend']>;
};
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 {
getIncomersBase,
getOutgoersBase,
getOverlappingArea,
isRectObject,
nodeToRect,
@@ -20,6 +18,7 @@ import {
import { useStore } from '$lib/store';
import type { Edge, FitViewOptions, Node } from '$lib/types';
import { isNode } from '$lib/utils';
export function useSvelteFlow(): {
zoomIn: ZoomInOut;
@@ -48,9 +47,16 @@ export function useSvelteFlow(): {
screenToFlowPosition: (position: XYPosition) => XYPosition;
flowToScreenPosition: (position: XYPosition) => XYPosition;
viewport: Writable<Viewport>;
getConnectedEdges: (id: string | (Node | { id: Node['id'] })[]) => Edge[];
getIncomers: (node: string | Node | { id: Node['id'] }) => Node[];
getOutgoers: (node: string | Node | { id: Node['id'] }) => Node[];
updateNode: (
id: string,
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 };
} {
const {
@@ -84,6 +90,24 @@ export function useSvelteFlow(): {
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 {
zoomIn,
zoomOut,
@@ -136,12 +160,12 @@ export function useSvelteFlow(): {
) => {
const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
if (!nodeRect || !node) {
if (!nodeRect) {
return [];
}
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;
}
@@ -232,29 +256,6 @@ export function useSvelteFlow(): {
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: () => {
return {
nodes: get(nodes).map((node) => ({
@@ -268,6 +269,16 @@ export function useSvelteFlow(): {
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
};
}
+13 -2
View File
@@ -7,7 +7,7 @@ export * from '$lib/container/Panel';
export * from '$lib/components/SvelteFlowProvider';
export * from '$lib/components/EdgeLabelRenderer';
export * from '$lib/components/BaseEdge';
export * from '$lib/components/edges';
export { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '$lib/components/edges';
export * from '$lib/components/Handle';
// plugins
@@ -27,9 +27,20 @@ export * from '$lib/hooks/useSvelteFlow';
export * from '$lib/hooks/useUpdateNodeInternals';
export * from '$lib/hooks/useConnection';
export * from '$lib/hooks/useNodesEdges';
export * from '$lib/hooks/useHandleConnections';
export * from '$lib/hooks/useNodesData';
// 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 { Node, NodeTypes, DefaultNodeOptions } from '$lib/types/nodes';
export type { SvelteFlowStore } from '$lib/store/types';
@@ -45,8 +45,8 @@
<svg
class={cc(['svelte-flow__background', className])}
data-testid="svelte-flow__background"
style:--background-color-props={bgColor}
style:--background-pattern-color-props={patternColor}
style:--xy-background-color-props={bgColor}
style:--xy-background-pattern-color-props={patternColor}
>
<pattern
id={patternId}
@@ -15,11 +15,11 @@
type="button"
on:click
class={cc(['svelte-flow__controls-button', className])}
style:--controls-button-background-color-props={bgColor}
style:--controls-button-background-color-hover-props={bgColorHover}
style:--controls-button-color-props={color}
style:--controls-button-color-hover-props={colorHover}
style:--controls-button-border-color-props={borderColor}
style:--xy-controls-button-background-color-props={bgColor}
style:--xy-controls-button-background-color-hover-props={bgColorHover}
style:--xy-controls-button-color-props={color}
style:--xy-controls-button-color-hover-props={colorHover}
style:--xy-controls-button-border-color-props={borderColor}
{...$$restProps}
>
<slot class="button-svg" />
@@ -94,10 +94,10 @@
viewBox="{x} {y} {viewboxWidth} {viewboxHeight}"
role="img"
aria-labelledby={labelledBy}
style:--minimap-background-color-props={bgColor}
style:--minimap-mask-color-props={maskColor}
style:--minimap-mask-stroke-color-props={maskStrokeColor}
style:--minimap-mask-stroke-width-props={maskStrokeWidth}
style:--xy-minimap-background-color-props={bgColor}
style:--xy-minimap-mask-color-props={maskColor}
style:--xy-minimap-mask-stroke-color-props={maskStrokeColor}
style:--xy-minimap-mask-stroke-width-props={maskStrokeWidth}
use:interactive={{
panZoom: $panZoom,
viewport,
+13 -8
View File
@@ -192,15 +192,20 @@ export function createStore({
}
function unselectNodesAndEdges(params?: { nodes?: Node[]; edges?: Edge[] }) {
const nodeIdsToUnselect = (params?.nodes ? params.nodes : get(store.nodes)).map(
(item) => item.id
);
const edgeIdsToUnselect = (params?.edges ? params.edges : get(store.edges)).map(
(item) => item.id
);
const selectedNodeIds = (params?.nodes ? params.nodes : get(store.nodes))
.filter((node) => node.selected)
.map((node) => node.id);
const selectedEdgeIds = (params?.edges ? params.edges : get(store.edges))
.filter((edge) => edge.selected)
.map((edge) => edge.id);
store.nodes.update((ns) => ns.map(resetSelectedItem(nodeIdsToUnselect)));
store.edges.update((es) => es.map(resetSelectedItem(edgeIdsToUnselect)));
if (selectedNodeIds.length) {
store.nodes.update((ns) => ns.map(resetSelectedItem(selectedNodeIds)));
}
if (selectedEdgeIds.length) {
store.edges.update((es) => es.map(resetSelectedItem(selectedEdgeIds)));
}
}
store.deleteKeyPressed.subscribe((deleteKeyPressed) => {
+29 -13
View File
@@ -17,17 +17,26 @@ import {
type Viewport,
updateNodes,
getNodesBounds,
getViewportForBounds
getViewportForBounds,
updateConnectionLookup,
type ConnectionLookup,
type OnConnect,
type OnConnectStart,
type OnConnectEnd
} from '@xyflow/system';
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
import InputNode from '$lib/components/nodes/InputNode.svelte';
import OutputNode from '$lib/components/nodes/OutputNode.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 SmoothStepEdge from '$lib/components/edges/SmoothStepEdge.svelte';
import StepEdge from '$lib/components/edges/StepEdge.svelte';
import {
BezierEdgeInternal,
SmoothStepEdgeInternal,
StraightEdgeInternal,
StepEdgeInternal
} from '$lib/components/edges';
import type {
NodeTypes,
EdgeTypes,
@@ -35,7 +44,8 @@ import type {
Node,
Edge,
FitViewOptions,
OnDelete
OnDelete,
OnEdgeCreate
} from '$lib/types';
import { createNodesStore, createEdgesStore } from './utils';
import { initConnectionProps, type ConnectionProps } from './derived-connection-props';
@@ -48,10 +58,10 @@ export const initialNodeTypes = {
};
export const initialEdgeTypes = {
straight: StraightEdge,
smoothstep: SmoothStepEdge,
default: BezierEdge,
step: StepEdge
straight: StraightEdgeInternal,
smoothstep: SmoothStepEdgeInternal,
default: BezierEdgeInternal,
step: StepEdgeInternal
};
export const getInitialStore = ({
@@ -67,11 +77,12 @@ export const getInitialStore = ({
height?: number;
fitView?: boolean;
}) => {
const nodeLookup = new Map<string, Node>();
const nodeLookup = new Map();
const nextNodes = updateNodes(nodes, nodeLookup, {
nodeOrigin: [0, 0],
elevateNodesOnSelect: false
});
const connectionLookup = updateConnectionLookup(new Map(), edges);
let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
@@ -86,8 +97,9 @@ export const getInitialStore = ({
nodes: createNodesStore(nextNodes, nodeLookup),
nodeLookup: readable<Map<string, Node>>(nodeLookup),
visibleNodes: readable<Node[]>([]),
edges: createEdgesStore(edges),
edges: createEdgesStore(edges, connectionLookup),
edgeTree: readable<GroupedEdges<EdgeLayouted>[]>([]),
connectionLookup: readable<ConnectionLookup>(connectionLookup),
height: writable<number>(500),
width: writable<number>(500),
minZoom: writable<number>(0.5),
@@ -130,6 +142,10 @@ export const getInitialStore = ({
lib: readable<string>('svelte'),
onlyRenderVisibleElements: writable<boolean>(false),
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,
get
} 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';
@@ -168,6 +174,7 @@ export const createNodesStore = (
export const createEdgesStore = (
edges: Edge[],
connectionLookup: ConnectionLookup,
defaultOptions?: DefaultEdgeOptions
): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => {
const { subscribe, set, update } = writable<Edge[]>([]);
@@ -176,6 +183,9 @@ export const createEdgesStore = (
const _set: typeof set = (eds: Edge[]) => {
const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;
updateConnectionLookup(connectionLookup, nextEdges);
value = nextEdges;
set(value);
};
+30 -2
View File
@@ -5,7 +5,9 @@ import type {
BezierPathOptions,
DefaultEdgeOptionsBase,
EdgePosition,
SmoothStepPathOptions
SmoothStepPathOptions,
Optional,
StepPathOptions
} from '@xyflow/system';
import type { Node } from '$lib/types';
@@ -29,6 +31,7 @@ type BezierEdgeType<T> = DefaultEdge<T> & {
type StepEdgeType<T> = DefaultEdge<T> & {
type: 'step';
pathOptions?: StepPathOptions;
};
export type Edge<T = any> =
@@ -37,7 +40,7 @@ export type Edge<T = any> =
| BezierEdgeType<T>
| StepEdgeType<T>;
export type EdgeProps = Omit<Edge, 'sourceHandle' | 'targetHandle'> &
export type EdgeProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHandle' | 'type'> &
EdgePosition & {
markerStart?: string;
markerEnd?: string;
@@ -45,6 +48,31 @@ export type EdgeProps = Omit<Edge, 'sourceHandle' | 'targetHandle'> &
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 DefaultEdgeOptions = Omit<DefaultEdgeOptionsBase<Edge>, 'focusable'>;
+5 -1
View File
@@ -4,7 +4,8 @@ import type {
HandleType,
Position,
XYPosition,
ConnectingHandle
ConnectingHandle,
Connection
} from '@xyflow/system';
import type { Node } from './nodes';
@@ -30,8 +31,11 @@ export type HandleComponentProps = {
isConnectable?: boolean;
isConnectableStart?: boolean;
isConnectableEnd?: boolean;
onconnect?: (connections: Connection[]) => void;
ondisconnect?: (connections: Connection[]) => void;
};
export type FitViewOptions = FitViewOptionsBase<Node>;
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';
export const isNode = isNodeBase<Node, Edge>;
export const isEdge = isEdgeBase<Node, Edge>;
export const isNode = isNodeBase<Node>;
export const isEdge = isEdgeBase<Edge>;
export const getOutgoers = getOutgoersBase<Node, Edge>;
export const getIncomers = getIncomersBase<Node, Edge>;
export const addEdge = addEdgeBase<Edge>;
+2 -1
View File
@@ -8,7 +8,8 @@
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
"strict": true,
"noErrorTruncation": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@xyflow/system",
"version": "0.0.11",
"version": "0.0.12",
"description": "xyflow core system that powers React Flow and Svelte Flow.",
"keywords": [
"node-based UI",
+12 -12
View File
@@ -1,38 +1,38 @@
.xy-flow {
--node-border-default: 1px solid #bbb;
--node-border-selected-default: 1px solid #555;
--xy-node-border-default: 1px solid #bbb;
--xy-node-border-selected-default: 1px solid #555;
--handle-background-color-default: #333;
--xy-handle-background-color-default: #333;
--selection-background-color-default: rgba(150, 150, 180, 0.1);
--selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);
--xy-selection-background-color-default: rgba(150, 150, 180, 0.1);
--xy-selection-border-default: 1px dotted rgba(155, 155, 155, 0.8);
}
.xy-flow.dark {
--node-color-default: #f8f8f8;
--xy-node-color-default: #f8f8f8;
}
.xy-flow__handle {
background-color: var(--handle-background-color, var(--handle-background-color-default));
background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
}
.xy-flow__node-input,
.xy-flow__node-default,
.xy-flow__node-output,
.xy-flow__node-group {
border: var(--node-border, var(--node-border-default));
color: var(--node-color, var(--node-color-default));
border: var(--xy-node-border, var(--xy-node-border-default));
color: var(--xy-node-color, var(--xy-node-color-default));
&.selected,
&:focus,
&:focus-visible {
outline: none;
border: var(--node-border-selected, var(--node-border-selected-default));
border: var(--xy-node-border-selected, var(--xy-node-border-selected-default));
}
}
.xy-flow__nodesselection-rect,
.xy-flow__selection {
background: var(--selection-background-color, var(--selection-background-color-default));
border: var(--selection-border, var(--selection-border-default));
background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
border: var(--xy-selection-border, var(--xy-selection-border-default));
}
+56 -52
View File
@@ -1,51 +1,55 @@
/* these are the necessary styles for React/Svelte Flow, they get used by base.css and style.css */
.xy-flow {
--edge-stroke-default: #b1b1b7;
--edge-stroke-width-default: 1;
--edge-stroke-selected-default: #555;
--xy-edge-stroke-default: #b1b1b7;
--xy-edge-stroke-width-default: 1;
--xy-edge-stroke-selected-default: #555;
--connectionline-stroke-default: #b1b1b7;
--connectionline-stroke-width-default: 1;
--xy-connectionline-stroke-default: #b1b1b7;
--xy-connectionline-stroke-width-default: 1;
--attribution-background-color-default: rgba(255, 255, 255, 0.5);
--xy-attribution-background-color-default: rgba(255, 255, 255, 0.5);
--minimap-background-color-default: #fff;
--minimap-mask-background-color-default: rgb(240, 240, 240, 0.6);
--minimap-node-background-color-default: #e2e2e2;
--minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2;
--xy-minimap-background-color-default: #fff;
--xy-minimap-mask-background-color-default: rgb(240, 240, 240, 0.6);
--xy-minimap-node-background-color-default: #e2e2e2;
--xy-minimap-node-stroke-color-default: transparent;
--xy-minimap-node-stroke-width-default: 2;
--background-color-default: transparent;
--background-pattern-dots-color-default: #91919a;
--background-pattern-lines-color-default: #eee;
--background-pattern-cross-color-default: #e2e2e2;
--xy-background-color-default: transparent;
--xy-background-pattern-dots-color-default: #91919a;
--xy-background-pattern-lines-color-default: #eee;
--xy-background-pattern-cross-color-default: #e2e2e2;
}
.xy-flow.dark {
--edge-stroke-default: #3c3c3c;
--edge-stroke-width-default: 1;
--edge-stroke-selected-default: #727272;
--xy-edge-stroke-default: #3e3e3e;
--xy-edge-stroke-width-default: 1;
--xy-edge-stroke-selected-default: #727272;
--connectionline-stroke-default: #b1b1b7;
--connectionline-stroke-width-default: 1;
--xy-connectionline-stroke-default: #b1b1b7;
--xy-connectionline-stroke-width-default: 1;
--attribution-background-color-default: rgba(150, 150, 150, 0.25);
--xy-attribution-background-color-default: rgba(150, 150, 150, 0.25);
--minimap-background-color-default: #141414;
--minimap-mask-background-color-default: rgb(60, 60, 60, 0.6);
--minimap-node-background-color-default: #2b2b2b;
--minimap-node-stroke-color-default: transparent;
--minimap-node-stroke-width-default: 2;
--xy-minimap-background-color-default: #141414;
--xy-minimap-mask-background-color-default: rgb(60, 60, 60, 0.6);
--xy-minimap-node-background-color-default: #2b2b2b;
--xy-minimap-node-stroke-color-default: transparent;
--xy-minimap-node-stroke-width-default: 2;
--background-color-default: #141414;
--background-pattern-dots-color-default: #777;
--background-pattern-lines-color-default: #777;
--background-pattern-cross-color-default: #777;
--xy-background-color-default: #141414;
--xy-background-pattern-dots-color-default: #777;
--xy-background-pattern-lines-color-default: #777;
--xy-background-pattern-cross-color-default: #777;
}
.xy-flow {
background-color: var(--background-color-props, var(--background-color-default, 'transparent'));
background-color: var(--xy-background-color, var(--xy-background-color-default));
}
.xy-flow__background {
background-color: var(--xy-background-color, var(--xy-background-color-props, var(--xy-background-color-default)));
}
.xy-flow__container {
@@ -94,14 +98,14 @@
}
.xy-flow__edge-path {
stroke: var(--edge-stroke, var(--edge-stroke-default));
stroke-width: var(--edge-stroke-width, var(--edge-stroke-width-default));
stroke: var(--xy-edge-stroke, var(--xy-edge-stroke-default));
stroke-width: var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));
fill: none;
}
.xy-flow__connection-path {
stroke: var(--connectionline-stroke, var(--connectionline-stroke-default));
stroke-width: var(--connectionline-stroke-width, var(--connectionline-stroke-width-default));
stroke: var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));
stroke-width: var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));
fill: none;
}
@@ -132,7 +136,7 @@
&.selected .xy-flow__edge-path,
&:focus .xy-flow__edge-path,
&:focus-visible .xy-flow__edge-path {
stroke: var(--edge-stroke-selected, var(--edge-stroke-selected-default));
stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
}
&-textwrapper {
@@ -266,7 +270,7 @@
.xy-flow__attribution {
font-size: 10px;
background: var(--attribution-background-color, var(--attribution-background-color-default));
background: var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));
padding: 2px 3px;
margin: 0;
@@ -293,27 +297,27 @@
}
.xy-flow__minimap {
background: var(--minimap-background-color, var(--minimap-background-color-default));
background: var(--xy-minimap-background-color, var(--xy-minimap-background-color-default));
&-mask {
fill: var(
--minimap-mask-background-color-props,
var(--minimap-mask-background-color, var(--minimap-mask-background-color-default))
--xy-minimap-mask-background-color-props,
var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default))
);
}
&-node {
fill: var(
--minimap-node-background-color-props,
var(--minimap-node-background-color, var(--minimap-node-background-color-default))
--xy-minimap-node-background-color-props,
var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default))
);
stroke: var(
--minimap-node-stroke-color-props,
var(--minimap-node-stroke-color, var(--minimap-node-stroke-color-default))
--xy-minimap-node-stroke-color-props,
var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default))
);
stroke-width: var(
--minimap-node-stroke-width-props,
var(--minimap-node-stroke-width, var(--minimap-node-stroke-width-default))
--xy-minimap-node-stroke-width-props,
var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default))
);
}
}
@@ -326,22 +330,22 @@
.xy-flow__background-pattern {
&.dots {
fill: var(
--background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-dots-color-default))
--xy-background-pattern-color-props,
var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default))
);
}
&.lines {
stroke: var(
--background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-lines-color-default))
--xy-background-pattern-color-props,
var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default))
);
}
&.cross {
stroke: var(
--background-pattern-color-props,
var(--background-pattern-color, var(--background-pattern-cross-color-default))
--xy-background-pattern-color-props,
var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default))
);
}
}
+56 -53
View File
@@ -1,46 +1,46 @@
.xy-flow {
--node-color-default: inherit;
--node-border-default: 1px solid #1a192b;
--node-background-color-default: #fff;
--node-group-background-color-default: rgba(240, 240, 240, 0.25);
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
--node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
--node-border-radius-default: 3px;
--xy-node-color-default: inherit;
--xy-node-border-default: 1px solid #1a192b;
--xy-node-background-color-default: #fff;
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, 0.08);
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #1a192b;
--xy-node-border-radius-default: 3px;
--handle-background-color-default: #1a192b;
--handle-border-color-default: #fff;
--xy-handle-background-color-default: #1a192b;
--xy-handle-border-color-default: #fff;
--selection-background-color-default: rgba(0, 89, 220, 0.08);
--selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
--xy-selection-background-color-default: rgba(0, 89, 220, 0.08);
--xy-selection-border-default: 1px dotted rgba(0, 89, 220, 0.8);
--controls-button-background-color-default: #fefefe;
--controls-button-background-color-hover-default: #f4f4f4;
--controls-button-color-default: inherit;
--controls-button-color-hover-default: inherit;
--controls-button-border-color-default: #eee;
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
--xy-controls-button-background-color-default: #fefefe;
--xy-controls-button-background-color-hover-default: #f4f4f4;
--xy-controls-button-color-default: inherit;
--xy-controls-button-color-hover-default: inherit;
--xy-controls-button-border-color-default: #eee;
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
}
.xy-flow.dark {
--node-color-default: #f8f8f8;
--node-border-default: 1px solid #3c3c3c;
--node-background-color-default: #1e1e1e;
--node-group-background-color-default: rgba(240, 240, 240, 0.25);
--node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
--node-boxshadow-selected-default: 0 0 0 0.5px #999;
--xy-node-color-default: #f8f8f8;
--xy-node-border-default: 1px solid #3c3c3c;
--xy-node-background-color-default: #1e1e1e;
--xy-node-group-background-color-default: rgba(240, 240, 240, 0.25);
--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, 0.08);
--xy-node-boxshadow-selected-default: 0 0 0 0.5px #999;
--handle-background-color-default: #bebebe;
--handle-border-color-default: #1e1e1e;
--xy-handle-background-color-default: #bebebe;
--xy-handle-border-color-default: #1e1e1e;
--selection-background-color-default: rgba(200, 200, 220, 0.08);
--selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
--xy-selection-background-color-default: rgba(200, 200, 220, 0.08);
--xy-selection-border-default: 1px dotted rgba(200, 200, 220, 0.8);
--controls-button-background-color-default: #2b2b2b;
--controls-button-background-color-hover-default: #3e3e3e;
--controls-button-color-default: #f8f8f8;
--controls-button-color-hover-default: #fff;
--controls-button-border-color-default: #5b5b5b;
--controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
--xy-controls-button-background-color-default: #2b2b2b;
--xy-controls-button-background-color-hover-default: #3e3e3e;
--xy-controls-button-color-default: #f8f8f8;
--xy-controls-button-color-hover-default: #fff;
--xy-controls-button-border-color-default: #5b5b5b;
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
}
.xy-flow__edge {
@@ -67,35 +67,35 @@
.xy-flow__node-output,
.xy-flow__node-group {
padding: 10px;
border-radius: var(--node-border-radius, var(--node-border-radius-default));
border-radius: var(--xy-node-border-radius, var(--xy-node-border-radius-default));
width: 150px;
font-size: 12px;
color: var(--node-color, var(--node-color-default));
color: var(--xy-node-color, var(--xy-node-color-default));
text-align: center;
border: var(--node-border, var(--node-border-default));
background-color: var(--node-background-color, var(--node-background-color-default));
border: var(--xy-node-border, var(--xy-node-border-default));
background-color: var(--xy-node-background-color, var(--xy-node-background-color-default));
&.selectable {
&:hover {
box-shadow: var(--node-boxshadow-hover, var(--node-boxshadow-hover-default));
box-shadow: var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default));
}
&.selected,
&:focus,
&:focus-visible {
box-shadow: var(--node-boxshadow-selected, var(--node-boxshadow-selected-default));
box-shadow: var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default));
}
}
}
.xy-flow__node-group {
background-color: var(--node-group-background-color, var(--node-group-background-color-default));
background-color: var(--xy-node-group-background-color, var(--xy-node-group-background-color-default));
}
.xy-flow__nodesselection-rect,
.xy-flow__selection {
background: var(--selection-background-color, var(--selection-background-color-default));
border: var(--selection-border, var(--selection-border-default));
background: var(--xy-selection-background-color, var(--xy-selection-background-color-default));
border: var(--xy-selection-border, var(--xy-selection-border-default));
&:focus,
&:focus-visible {
@@ -106,34 +106,37 @@
.xy-flow__handle {
width: 6px;
height: 6px;
background-color: var(--handle-background-color, var(--handle-background-color-default));
border: 1px solid var(--handle-border-color, var(--handle-border-color-default));
background-color: var(--xy-handle-background-color, var(--xy-handle-background-color-default));
border: 1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));
border-radius: 100%;
}
.xy-flow__controls {
box-shadow: var(--controls-box-shadow, var(--controls-box-shadow-default));
box-shadow: var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default));
&-button {
border: none;
background: var(--controls-button-background-color, var(--controls-button-background-color-default));
background: var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));
border-bottom: 1px solid
var(
--controls-button-border-color-props,
var(--controls-button-border-color, var(--controls-button-border-color-default))
--xy-controls-button-border-color-props,
var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default))
);
color: var(--controls-button-color-props, var(--controls-button-color, var(--controls-button-color-default)));
color: var(
--xy-controls-button-color-props,
var(--xy-controls-button-color, var(--xy-controls-button-color-default))
);
cursor: pointer;
user-select: none;
&:hover {
background: var(
--controls-button-background-color-hover-props,
var(--controls-button-background-color-hover, var(--controls-button-background-color-hover-default))
--xy-controls-button-background-color-hover-props,
var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default))
);
color: var(
--controls-button-color-hover-props,
var(--controls-button-color-hover, var(--controls-button-color-hover-default))
--xy-controls-button-color-hover-props,
var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default))
);
}
+4
View File
@@ -27,6 +27,10 @@ export type SmoothStepPathOptions = {
borderRadius?: number;
};
export type StepPathOptions = {
offset?: number;
};
export type BezierPathOptions = {
curvature?: number;
};
+4 -2
View File
@@ -22,8 +22,8 @@ export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => vo
export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void;
export type Connection = {
source: string | null;
target: string | null;
source: string;
target: string;
sourceHandle: string | null;
targetHandle: string | null;
};
@@ -139,3 +139,5 @@ export type UpdateConnection = (params: {
export type ColorModeClass = 'light' | 'dark';
export type ColorMode = ColorModeClass | 'system';
export type ConnectionLookup = Map<string, Map<string, Connection>>;
+2
View File
@@ -1,3 +1,5 @@
import type { Optional } from '../utils/types';
export enum Position {
Left = 'left',
Top = 'top',
+53
View File
@@ -0,0 +1,53 @@
import { Connection } from '../types';
/**
* @internal
*/
export function areConnectionMapsEqual(a?: Map<string, Connection>, b?: Map<string, Connection>) {
if (!a && !b) {
return true;
}
if (!a || !b || a.size !== b.size) {
return false;
}
if (!a.size && !b.size) {
return true;
}
for (const key of a.keys()) {
if (!b.has(key)) {
return false;
}
}
return true;
}
/**
* We call the callback for all connections in a that are not in b
*
* @internal
*/
export function handleConnectionChange(
a: Map<string, Connection>,
b: Map<string, Connection>,
cb?: (diff: Connection[]) => void
) {
if (!cb) {
return;
}
const diff: Connection[] = [];
a.forEach((connection, key) => {
if (!b?.has(key)) {
diff.push(connection);
}
});
if (diff.length) {
cb(diff);
}
}
+9 -1
View File
@@ -112,7 +112,7 @@ export function isEdgeVisible({ sourceNode, targetNode, width, height, transform
}
const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection | EdgeBase): string =>
`xyflow__edge-${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;
`xy-edge__${source}${sourceHandle || ''}-${target}${targetHandle || ''}`;
const connectionExists = (edge: EdgeBase, edges: EdgeBase[]) => {
return edges.some(
@@ -148,6 +148,14 @@ export const addEdgeBase = <EdgeType extends EdgeBase>(
return edges;
}
if (edge.sourceHandle === null) {
delete edge.sourceHandle;
}
if (edge.targetHandle === null) {
delete edge.targetHandle;
}
return edges.concat(edge);
};
+4 -7
View File
@@ -11,7 +11,6 @@ import {
getViewportForBounds,
} from './general';
import {
type Connection,
type Transform,
type XYPosition,
type Rect,
@@ -26,13 +25,11 @@ import {
} from '../types';
import { errorMessages } from '../constants';
export const isEdgeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
element: NodeType | Connection | EdgeType
): element is EdgeType => 'id' in element && 'source' in element && 'target' in element;
export const isEdgeBase = <EdgeType extends EdgeBase = EdgeBase>(element: any): element is EdgeType =>
'id' in element && 'source' in element && 'target' in element;
export const isNodeBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
element: NodeType | Connection | EdgeType
): element is NodeType => 'id' in element && !('source' in element) && !('target' in element);
export const isNodeBase = <NodeType extends NodeBase = NodeBase>(element: any): element is NodeType =>
'id' in element && !('source' in element) && !('target' in element);
export const getOutgoersBase = <NodeType extends NodeBase = NodeBase, EdgeType extends EdgeBase = EdgeBase>(
node: NodeType | { id: string },
+2
View File
@@ -1,3 +1,4 @@
export * from './connections';
export * from './dom';
export * from './edges';
export * from './graph';
@@ -5,3 +6,4 @@ export * from './general';
export * from './marker';
export * from './node-toolbar';
export * from './store';
export * from './types';
+25 -1
View File
@@ -9,6 +9,8 @@ import {
Transform,
XYPosition,
XYZPosition,
ConnectionLookup,
EdgeBase,
} from '../types';
import { getDimensions, getHandleBounds } from './dom';
import { isNumeric } from './general';
@@ -71,11 +73,13 @@ export function updateNodes<NodeType extends NodeBase>(
defaults: {},
}
): NodeType[] {
const tmpLookup = new Map(nodeLookup);
nodeLookup.clear();
const parentNodes: ParentNodes = {};
const selectedNodeZ: number = options?.elevateNodesOnSelect ? 1000 : 0;
const nextNodes = nodes.map((n) => {
const currentStoreNode = nodeLookup.get(n.id);
const currentStoreNode = tmpLookup.get(n.id);
const node: NodeType = {
...options.defaults,
...n,
@@ -233,3 +237,23 @@ export function panBy({
return transformChanged;
}
export function updateConnectionLookup(lookup: ConnectionLookup, edges: EdgeBase[]) {
lookup.clear();
edges.forEach(({ source, target, sourceHandle = null, targetHandle = null }) => {
if (source && target) {
const sourceKey = `${source}-source-${sourceHandle}`;
const targetKey = `${target}-target-${targetHandle}`;
const prevSource = lookup.get(sourceKey) || new Map();
const prevTarget = lookup.get(targetKey) || new Map();
const connection = { source, target, sourceHandle, targetHandle };
lookup.set(sourceKey, prevSource.set(`${target}-${targetHandle}`, connection));
lookup.set(targetKey, prevTarget.set(`${source}-${sourceHandle}`, connection));
}
});
return lookup;
}
+7 -5
View File
@@ -58,12 +58,10 @@ export type XYHandleInstance = {
type Result = {
handleDomNode: Element | null;
isValid: boolean;
connection: Connection;
connection: Connection | null;
endHandle: ConnectingHandle | null;
};
const nullConnection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null };
const alwaysValid = () => true;
let connectionStartHandle: ConnectingHandle | null = null;
@@ -197,7 +195,7 @@ function onPointerDown(
return resetRecentHandle(prevActiveHandle, lib);
}
if (connection.source !== connection.target && handleDomNode) {
if (connection?.source !== connection?.target && handleDomNode) {
resetRecentHandle(prevActiveHandle, lib);
prevActiveHandle = handleDomNode;
handleDomNode.classList.add('connecting', `${lib}-flow__handle-connecting`);
@@ -269,7 +267,7 @@ function isValidHandle(
const result: Result = {
handleDomNode: handleToCheck,
isValid: false,
connection: nullConnection,
connection: null,
endHandle: null,
};
@@ -280,6 +278,10 @@ function isValidHandle(
const connectable = handleToCheck.classList.contains('connectable');
const connectableEnd = handleToCheck.classList.contains('connectableend');
if (!handleNodeId) {
return result;
}
const connection: Connection = {
source: isTarget ? handleNodeId : fromNodeId,
sourceHandle: isTarget ? handleId : fromHandleId,
+145 -43
View File
@@ -61,10 +61,10 @@ importers:
dependencies:
'@astrojs/react':
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':
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':
specifier: ^18.2.24
version: registry.npmjs.org/@types/react@18.2.24
@@ -291,8 +291,8 @@ importers:
packages/svelte:
dependencies:
'@svelte-put/shortcut':
specifier: ^3.0.0
version: registry.npmjs.org/@svelte-put/shortcut@3.0.0
specifier: ^3.1.0
version: registry.npmjs.org/@svelte-put/shortcut@3.1.0
'@xyflow/system':
specifier: workspace:*
version: link:../system
@@ -305,7 +305,7 @@ importers:
version: registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6)
'@sveltejs/kit':
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':
specifier: ^2.2.1
version: registry.npmjs.org/@sveltejs/package@2.2.1(svelte@4.2.1)(typescript@5.1.3)
@@ -417,7 +417,7 @@ importers:
dependencies:
'@playwright/experimental-ct-react':
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':
specifier: ^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
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}
id: registry.npmjs.org/@astrojs/react/3.0.2
name: '@astrojs/react'
@@ -565,7 +565,7 @@ packages:
dependencies:
'@types/react': registry.npmjs.org/@types/react@18.2.24
'@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-dom: registry.npmjs.org/react-dom@18.2.0(react@18.2.0)
ultrahtml: registry.npmjs.org/ultrahtml@1.5.2
@@ -574,7 +574,7 @@ packages:
- vite
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}
id: registry.npmjs.org/@astrojs/svelte/4.0.2
name: '@astrojs/svelte'
@@ -584,10 +584,10 @@ packages:
astro: ^3.0.11
svelte: ^3.55.0 || ^4.0.0
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
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:
- supports-color
- typescript
@@ -1938,7 +1938,7 @@ packages:
- terser
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}
id: registry.npmjs.org/@playwright/experimental-ct-react/1.39.0
name: '@playwright/experimental-ct-react'
@@ -1947,7 +1947,7 @@ packages:
hasBin: true
dependencies:
'@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:
- '@types/node'
- less
@@ -2120,10 +2120,10 @@ packages:
version: 2.0.0
dev: true
registry.npmjs.org/@svelte-put/shortcut@3.0.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}
registry.npmjs.org/@svelte-put/shortcut@3.1.0:
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'
version: 3.0.0
version: 3.1.0
dev: false
registry.npmjs.org/@sveltejs/adapter-auto@2.1.0(@sveltejs/kit@1.22.6):
@@ -2134,7 +2134,7 @@ packages:
peerDependencies:
'@sveltejs/kit': ^1.0.0
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
dev: true
@@ -2150,7 +2150,7 @@ packages:
import-meta-resolve: registry.npmjs.org/import-meta-resolve@4.0.0
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}
id: registry.npmjs.org/@sveltejs/kit/1.22.6
name: '@sveltejs/kit'
@@ -2162,7 +2162,7 @@ packages:
svelte: ^3.54.0 || ^4.0.0-next.0
vite: ^4.0.0
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
cookie: registry.npmjs.org/cookie@0.5.0
devalue: registry.npmjs.org/devalue@4.3.2
@@ -2175,7 +2175,7 @@ packages:
sirv: registry.npmjs.org/sirv@2.0.3
svelte: registry.npmjs.org/svelte@4.2.1
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:
- supports-color
dev: true
@@ -2231,7 +2231,7 @@ packages:
- typescript
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}
id: registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/1.0.4
name: '@sveltejs/vite-plugin-svelte-inspector'
@@ -2242,10 +2242,10 @@ packages:
svelte: ^3.54.0 || ^4.0.0
vite: ^4.0.0
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)
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:
- supports-color
@@ -2268,7 +2268,7 @@ packages:
- supports-color
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}
id: registry.npmjs.org/@sveltejs/vite-plugin-svelte/2.4.6
name: '@sveltejs/vite-plugin-svelte'
@@ -2278,15 +2278,15 @@ packages:
svelte: ^3.54.0 || ^4.0.0
vite: ^4.0.0
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)
deepmerge: registry.npmjs.org/deepmerge@4.3.1
kleur: registry.npmjs.org/kleur@4.1.5
magic-string: registry.npmjs.org/magic-string@0.30.5
svelte: registry.npmjs.org/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)
vitefu: registry.npmjs.org/vitefu@0.2.5(vite@4.5.0)
vite: registry.npmjs.org/vite@4.5.1(@types/node@18.7.16)
vitefu: registry.npmjs.org/vitefu@0.2.5(vite@4.5.1)
transitivePeerDependencies:
- supports-color
@@ -2972,6 +2972,12 @@ packages:
version: 7.5.4
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:
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'
@@ -2996,10 +3002,10 @@ packages:
version: 3.0.1
dev: false
registry.npmjs.org/@types/yauzl@2.10.2:
resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.2.tgz}
registry.npmjs.org/@types/yauzl@2.10.3:
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'
version: 2.10.2
version: 2.10.3
requiresBuild: true
dependencies:
'@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)
eslint: registry.npmjs.org/eslint@8.43.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
semver: registry.npmjs.org/semver@7.5.4
ts-api-utils: registry.npmjs.org/ts-api-utils@1.0.3(typescript@5.1.3)
@@ -3398,7 +3404,7 @@ packages:
dependencies:
'@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/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/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)
@@ -3420,7 +3426,7 @@ packages:
dependencies:
'@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/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/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)
@@ -3498,6 +3504,26 @@ packages:
vite: registry.npmjs.org/vite@4.5.0(@types/node@18.7.16)
transitivePeerDependencies:
- 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):
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
object-inspect: registry.npmjs.org/object-inspect@1.13.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
safe-array-concat: registry.npmjs.org/safe-array-concat@1.0.1
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
yauzl: registry.npmjs.org/yauzl@2.10.0
optionalDependencies:
'@types/yauzl': registry.npmjs.org/@types/yauzl@2.10.2
'@types/yauzl': registry.npmjs.org/@types/yauzl@2.10.3
transitivePeerDependencies:
- supports-color
dev: true
@@ -6487,7 +6513,7 @@ packages:
array-union: registry.npmjs.org/array-union@2.1.0
dir-glob: registry.npmjs.org/dir-glob@3.0.1
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
slash: registry.npmjs.org/slash@3.0.0
dev: true
@@ -6500,7 +6526,7 @@ packages:
dependencies:
dir-glob: registry.npmjs.org/dir-glob@3.0.1
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
slash: registry.npmjs.org/slash@4.0.0
dev: true
@@ -6791,6 +6817,13 @@ packages:
engines: {node: '>= 4'}
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:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz}
name: immediate
@@ -7431,7 +7464,7 @@ packages:
dependencies:
array-includes: registry.npmjs.org/array-includes@3.1.7
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
dev: true
@@ -8560,10 +8593,10 @@ packages:
engines: {node: '>= 0.4'}
dev: true
registry.npmjs.org/object.assign@4.1.4:
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}
registry.npmjs.org/object.assign@4.1.5:
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
version: 4.1.4
version: 4.1.5
engines: {node: '>= 0.4'}
dependencies:
call-bind: registry.npmjs.org/call-bind@1.0.5
@@ -9487,6 +9520,16 @@ packages:
picocolors: registry.npmjs.org/picocolors@1.0.0
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:
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
@@ -11206,7 +11249,7 @@ packages:
typescript: registry.npmjs.org/typescript@5.1.3
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}
id: registry.npmjs.org/svelte2tsx/0.6.23
name: svelte2tsx
@@ -11218,7 +11261,7 @@ packages:
dedent-js: registry.npmjs.org/dedent-js@1.0.1
pascal-case: registry.npmjs.org/pascal-case@3.1.2
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
registry.npmjs.org/svelte@4.2.1:
@@ -11755,6 +11798,14 @@ packages:
engines: {node: '>=14.17'}
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:
resolution: {integrity: sha512-qh4mBffhlkiXwDAOxvSGxhL0QEQsTbnP9BozOK3OYPEGvPvdWzvAUaXNtUSMdNsKDtuyjEbyVUPFZ52SSLhLqw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.2.tgz}
name: ultrahtml
@@ -12090,6 +12141,44 @@ packages:
optionalDependencies:
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):
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
@@ -12103,6 +12192,19 @@ packages:
dependencies:
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:
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

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