Merge branch 'next' into refactor/tsdoc
This commit is contained in:
@@ -1,12 +1,40 @@
|
||||
## 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
|
||||
|
||||
There are some breaking changes again (sorry!) but we are very close to the final API for Svelte Flow 1.0.0. The biggest change is that we group node attriubutes (`width`, `height`, `positionAbsolute`) that are added by the library under `node.computed`. This makes it easier to understand, that this stuff comes from the library itself. `node.width` and `node.height` is still an optional node option and can be used to set certain dimensions for SSR or on the client.
|
||||
This is a huge update! We added a new `<NodeToolbar />` component and a new `colorMode` ('light' | 'dark' | 'system') prop for toggling dark/light mode.
|
||||
|
||||
There are also some breaking changes again (sorry!) but we are very close to the final API for Svelte Flow 1.0.0. The biggest change is that we group node attriubutes (`width`, `height`, `positionAbsolute`) that are added by the library under `node.computed`. This makes it easier to understand, that this stuff comes from the library itself. `node.width` and `node.height` is still an optional node option and can be used to set certain dimensions for SSR or on the client.
|
||||
|
||||
- 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
|
||||
- ⚠️ `node.width/height` and `node.positionAbsolute` can now be found under `node.computed.width/height/positionAbsolute`
|
||||
- ⚠️ `node.width/height` is still optional an can be used for forcing certain dimensions and SSR
|
||||
@@ -15,7 +43,7 @@ There are some breaking changes again (sorry!) but we are very close to the fina
|
||||
|
||||
## 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]`)
|
||||
@@ -64,7 +92,7 @@ There are some breaking changes again (sorry!) but we are very close to the fina
|
||||
|
||||
## 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
|
||||
@@ -97,7 +125,7 @@ There are some breaking changes again (sorry!) but we are very close to the fina
|
||||
|
||||
## 0.0.18
|
||||
|
||||
- add `nodesDraggable` prop
|
||||
- add `nodesDraggable` prop
|
||||
- minimap: add default background
|
||||
|
||||
## 0.0.17
|
||||
@@ -110,7 +138,7 @@ There are some breaking changes again (sorry!) but we are very close to the fina
|
||||
|
||||
## 0.0.15
|
||||
|
||||
- fix wrongly displayed connectionline
|
||||
- fix wrongly displayed connectionline
|
||||
|
||||
## 0.0.14
|
||||
|
||||
@@ -149,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 />`
|
||||
- additional components: `<MiniMap />`, `<Controls />` & `<Background />`
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
export let target: $$Props['target'] = '';
|
||||
export let data: $$Props['data'] = {};
|
||||
export let style: $$Props['style'] = undefined;
|
||||
export let zIndex: $$Props['zIndex'] = undefined;
|
||||
|
||||
export let animated: $$Props['animated'] = false;
|
||||
export let selected: $$Props['selected'] = false;
|
||||
@@ -95,42 +96,44 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
||||
{#if !hidden}
|
||||
<g
|
||||
class={cc(['svelte-flow__edge', className])}
|
||||
class:animated
|
||||
class:selected
|
||||
data-id={id}
|
||||
on:click={onClick}
|
||||
on:contextmenu={onContextMenu}
|
||||
aria-label={ariaLabel === null
|
||||
? undefined
|
||||
: ariaLabel
|
||||
? ariaLabel
|
||||
: `Edge from ${source} to ${target}`}
|
||||
role="img"
|
||||
>
|
||||
<svelte:component
|
||||
this={edgeComponent}
|
||||
{id}
|
||||
{source}
|
||||
{target}
|
||||
{sourceX}
|
||||
{sourceY}
|
||||
{targetX}
|
||||
{targetY}
|
||||
{sourcePosition}
|
||||
{targetPosition}
|
||||
{animated}
|
||||
{selected}
|
||||
{label}
|
||||
{labelStyle}
|
||||
{data}
|
||||
{style}
|
||||
{interactionWidth}
|
||||
sourceHandleId={sourceHandle}
|
||||
targetHandleId={targetHandle}
|
||||
markerStart={markerStartUrl}
|
||||
markerEnd={markerEndUrl}
|
||||
/>
|
||||
</g>
|
||||
<svg style:zIndex>
|
||||
<g
|
||||
class={cc(['svelte-flow__edge', className])}
|
||||
class:animated
|
||||
class:selected
|
||||
data-id={id}
|
||||
on:click={onClick}
|
||||
on:contextmenu={onContextMenu}
|
||||
aria-label={ariaLabel === null
|
||||
? undefined
|
||||
: ariaLabel
|
||||
? ariaLabel
|
||||
: `Edge from ${source} to ${target}`}
|
||||
role="img"
|
||||
>
|
||||
<svelte:component
|
||||
this={edgeComponent}
|
||||
{id}
|
||||
{source}
|
||||
{target}
|
||||
{sourceX}
|
||||
{sourceY}
|
||||
{targetX}
|
||||
{targetY}
|
||||
{sourcePosition}
|
||||
{targetPosition}
|
||||
{animated}
|
||||
{selected}
|
||||
{label}
|
||||
{labelStyle}
|
||||
{data}
|
||||
{style}
|
||||
{interactionWidth}
|
||||
sourceHandleId={sourceHandle}
|
||||
targetHandleId={targetHandle}
|
||||
markerStart={markerStartUrl}
|
||||
markerEnd={markerEndUrl}
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
{/if}
|
||||
|
||||
@@ -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 {
|
||||
@@ -59,7 +50,12 @@
|
||||
panBy,
|
||||
cancelConnection,
|
||||
updateConnection,
|
||||
autoPanOnConnect
|
||||
autoPanOnConnect,
|
||||
edges,
|
||||
connectionLookup,
|
||||
onconnect: onConnectAction,
|
||||
onconnectstart: onConnectStartAction,
|
||||
onconnectend: onConnectEndAction
|
||||
} = store;
|
||||
|
||||
function onPointerDown(event: MouseEvent | TouchEvent) {
|
||||
@@ -88,26 +84,43 @@
|
||||
}
|
||||
|
||||
addEdge(edge);
|
||||
// @todo: should we change/ improve the stuff we are passing here?
|
||||
// instead of source/target we could pass fromNodeId, fromHandleId, etc
|
||||
dispatch('connect', { connection });
|
||||
$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'
|
||||
|
||||
@@ -191,12 +191,10 @@
|
||||
{dragging}
|
||||
{dragHandle}
|
||||
isConnectable={connectable}
|
||||
positionAbsolute={{ x: positionX, y: positionY }}
|
||||
positionAbsoluteX={positionX}
|
||||
positionAbsoluteY={positionY}
|
||||
{width}
|
||||
{height}
|
||||
on:connectstart
|
||||
on:connect
|
||||
on:connectend
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
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 positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
|
||||
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
|
||||
// @todo: there must be a better way to do this
|
||||
@@ -33,10 +31,11 @@
|
||||
zIndex;
|
||||
dragging;
|
||||
dragHandle;
|
||||
positionAbsolute;
|
||||
positionAbsoluteX;
|
||||
positionAbsoluteY;
|
||||
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} />
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
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 positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
|
||||
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
|
||||
// @todo: there must be a better way to do this
|
||||
@@ -33,6 +31,7 @@
|
||||
zIndex;
|
||||
dragging;
|
||||
dragHandle;
|
||||
positionAbsolute;
|
||||
positionAbsoluteX;
|
||||
positionAbsoluteY;
|
||||
isConnectable;
|
||||
</script>
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
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 positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
|
||||
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
|
||||
// @todo: there must be a better way to do this
|
||||
@@ -34,9 +32,10 @@
|
||||
zIndex;
|
||||
dragging;
|
||||
dragHandle;
|
||||
positionAbsolute;
|
||||
positionAbsoluteX;
|
||||
positionAbsoluteY;
|
||||
isConnectable;
|
||||
</script>
|
||||
|
||||
{data?.label}
|
||||
<Handle type="source" position={sourcePosition} on:connectstart on:connect on:connectend />
|
||||
<Handle type="source" position={sourcePosition} />
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
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 positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
|
||||
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
|
||||
// @todo: there must be a better way to do this
|
||||
@@ -31,9 +32,10 @@
|
||||
zIndex;
|
||||
dragging;
|
||||
dragHandle;
|
||||
positionAbsolute;
|
||||
positionAbsoluteX;
|
||||
positionAbsoluteY;
|
||||
isConnectable;
|
||||
</script>
|
||||
|
||||
{data?.label}
|
||||
<Handle type="target" position={targetPosition} on:connectstart on:connect on:connectend />
|
||||
<Handle type="target" position={targetPosition} />
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
const {
|
||||
elementsSelectable,
|
||||
edgeTree,
|
||||
visibleEdges,
|
||||
edges: { setDefaultOptions }
|
||||
} = useStore();
|
||||
|
||||
@@ -18,57 +18,47 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
{#each $edgeTree as group (group.level)}
|
||||
<svg style="z-index: {group.level}" class="svelte-flow__edges">
|
||||
{#if group.isMaxLevel} <MarkerDefinition />{/if}
|
||||
<g>
|
||||
{#each group.edges as edge (edge.id)}
|
||||
{@const edgeType = edge.type || 'default'}
|
||||
{@const selectable = !!(
|
||||
edge.selectable ||
|
||||
($elementsSelectable && typeof edge.selectable === 'undefined')
|
||||
)}
|
||||
|
||||
<EdgeWrapper
|
||||
id={edge.id}
|
||||
source={edge.source}
|
||||
target={edge.target}
|
||||
data={edge.data}
|
||||
style={edge.style}
|
||||
animated={edge.animated}
|
||||
selected={edge.selected}
|
||||
hidden={edge.hidden}
|
||||
label={edge.label}
|
||||
labelStyle={edge.labelStyle}
|
||||
markerStart={edge.markerStart}
|
||||
markerEnd={edge.markerEnd}
|
||||
sourceHandle={edge.sourceHandle}
|
||||
targetHandle={edge.targetHandle}
|
||||
sourceX={edge.sourceX}
|
||||
sourceY={edge.sourceY}
|
||||
targetX={edge.targetX}
|
||||
targetY={edge.targetY}
|
||||
sourcePosition={edge.sourcePosition}
|
||||
targetPosition={edge.targetPosition}
|
||||
ariaLabel={edge.ariaLabel}
|
||||
interactionWidth={edge.interactionWidth}
|
||||
class={edge.class}
|
||||
type={edgeType}
|
||||
{selectable}
|
||||
on:edgeclick
|
||||
on:edgecontextmenu
|
||||
/>
|
||||
{/each}
|
||||
</g>
|
||||
<div class="svelte-flow__edges">
|
||||
<svg class="svelte-flow__marker">
|
||||
<MarkerDefinition />
|
||||
</svg>
|
||||
{/each}
|
||||
|
||||
<style>
|
||||
.svelte-flow__edges {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
{#each $visibleEdges as edge (edge.id)}
|
||||
{@const edgeType = edge.type || 'default'}
|
||||
{@const selectable = !!(
|
||||
edge.selectable ||
|
||||
($elementsSelectable && typeof edge.selectable === 'undefined')
|
||||
)}
|
||||
|
||||
<EdgeWrapper
|
||||
id={edge.id}
|
||||
source={edge.source}
|
||||
target={edge.target}
|
||||
data={edge.data}
|
||||
style={edge.style}
|
||||
animated={edge.animated}
|
||||
selected={edge.selected}
|
||||
hidden={edge.hidden}
|
||||
label={edge.label}
|
||||
labelStyle={edge.labelStyle}
|
||||
markerStart={edge.markerStart}
|
||||
markerEnd={edge.markerEnd}
|
||||
sourceHandle={edge.sourceHandle}
|
||||
targetHandle={edge.targetHandle}
|
||||
sourceX={edge.sourceX}
|
||||
sourceY={edge.sourceY}
|
||||
targetX={edge.targetX}
|
||||
targetY={edge.targetY}
|
||||
sourcePosition={edge.sourcePosition}
|
||||
targetPosition={edge.targetPosition}
|
||||
ariaLabel={edge.ariaLabel}
|
||||
interactionWidth={edge.interactionWidth}
|
||||
class={edge.class}
|
||||
type={edgeType}
|
||||
zIndex={edge.zIndex}
|
||||
{selectable}
|
||||
on:edgeclick
|
||||
on:edgecontextmenu
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -83,9 +83,6 @@
|
||||
on:nodemouseenter
|
||||
on:nodemousemove
|
||||
on:nodemouseleave
|
||||
on:connectstart
|
||||
on:connect
|
||||
on:connectend
|
||||
on:nodedrag
|
||||
on:nodedragstart
|
||||
on:nodedragstop
|
||||
|
||||
@@ -78,6 +78,9 @@
|
||||
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';
|
||||
|
||||
@@ -152,7 +155,10 @@
|
||||
ondelete,
|
||||
onedgecreate,
|
||||
connectionMode,
|
||||
nodeDragThreshold
|
||||
nodeDragThreshold,
|
||||
onconnect,
|
||||
onconnectstart,
|
||||
onconnectend
|
||||
};
|
||||
|
||||
updateStoreByKeys(store, updatableProps);
|
||||
@@ -217,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 {
|
||||
@@ -92,4 +95,8 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
||||
ondelete?: OnDelete;
|
||||
|
||||
onedgecreate?: OnEdgeCreate;
|
||||
|
||||
onconnect?: OnConnect;
|
||||
onconnectstart?: OnConnectStart;
|
||||
onconnectend?: OnConnectEnd;
|
||||
};
|
||||
|
||||
@@ -66,6 +66,9 @@ export type UpdatableStoreProps = {
|
||||
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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -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,
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ 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 {
|
||||
|
||||
@@ -24,7 +24,7 @@ import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions, ConnectionData }
|
||||
import { initialEdgeTypes, initialNodeTypes, getInitialStore } from './initial-store';
|
||||
import type { SvelteFlowStore } from './types';
|
||||
import { syncNodeStores, syncEdgeStores, syncViewportStores } from './utils';
|
||||
import { getEdgeTree } from './edge-tree';
|
||||
import { getVisibleEdges } from './visible-edges';
|
||||
import { getVisibleNodes } from './visible-nodes';
|
||||
import { getDerivedConnectionProps } from './derived-connection-props';
|
||||
|
||||
@@ -357,8 +357,8 @@ export function createStore({
|
||||
...store,
|
||||
|
||||
// derived state
|
||||
edgeTree: getEdgeTree(store),
|
||||
connection: getDerivedConnectionProps(store, currentConnection),
|
||||
visibleEdges: getVisibleEdges(store),
|
||||
visibleNodes: getVisibleNodes(store),
|
||||
markers: derived(
|
||||
[store.edges, store.defaultMarkerColor, store.flowId],
|
||||
|
||||
@@ -4,20 +4,25 @@ import {
|
||||
SelectionMode,
|
||||
ConnectionMode,
|
||||
ConnectionLineType,
|
||||
devWarn,
|
||||
adoptUserProvidedNodes,
|
||||
getNodesBounds,
|
||||
getViewportForBounds,
|
||||
updateConnectionLookup,
|
||||
type SelectionRect,
|
||||
type SnapGrid,
|
||||
type MarkerProps,
|
||||
type PanZoomInstance,
|
||||
type CoordinateExtent,
|
||||
type IsValidConnection,
|
||||
type GroupedEdges,
|
||||
type NodeOrigin,
|
||||
type OnError,
|
||||
devWarn,
|
||||
type Viewport,
|
||||
updateNodes,
|
||||
getNodesBounds,
|
||||
getViewportForBounds
|
||||
type ConnectionLookup,
|
||||
type OnConnect,
|
||||
type OnConnectStart,
|
||||
type OnConnectEnd,
|
||||
type NodeLookup
|
||||
} from '@xyflow/system';
|
||||
|
||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||
@@ -72,11 +77,14 @@ export const getInitialStore = ({
|
||||
height?: number;
|
||||
fitView?: boolean;
|
||||
}) => {
|
||||
const nodeLookup = new Map<string, Node>();
|
||||
const nextNodes = updateNodes(nodes, nodeLookup, {
|
||||
const nodeLookup = new Map();
|
||||
const nextNodes = adoptUserProvidedNodes(nodes, nodeLookup, {
|
||||
nodeOrigin: [0, 0],
|
||||
elevateNodesOnSelect: false
|
||||
});
|
||||
const connectionLookup = new Map();
|
||||
const edgeLookup = new Map();
|
||||
updateConnectionLookup(connectionLookup, edgeLookup, edges);
|
||||
|
||||
let viewport: Viewport = { x: 0, y: 0, zoom: 1 };
|
||||
|
||||
@@ -89,16 +97,17 @@ export const getInitialStore = ({
|
||||
return {
|
||||
flowId: writable<string | null>(null),
|
||||
nodes: createNodesStore(nextNodes, nodeLookup),
|
||||
nodeLookup: readable<Map<string, Node>>(nodeLookup),
|
||||
nodeLookup: readable<NodeLookup>(nodeLookup),
|
||||
visibleNodes: readable<Node[]>([]),
|
||||
edges: createEdgesStore(edges),
|
||||
edgeTree: readable<GroupedEdges<EdgeLayouted>[]>([]),
|
||||
edges: createEdgesStore(edges, connectionLookup, edgeLookup),
|
||||
visibleEdges: readable<EdgeLayouted[]>([]),
|
||||
connectionLookup: readable<ConnectionLookup>(connectionLookup),
|
||||
height: writable<number>(500),
|
||||
width: writable<number>(500),
|
||||
minZoom: writable<number>(0.5),
|
||||
maxZoom: writable<number>(2),
|
||||
nodeOrigin: writable<NodeOrigin>([0, 0]),
|
||||
nodeDragThreshold: writable<number>(0),
|
||||
nodeDragThreshold: writable<number>(1),
|
||||
nodeExtent: writable<CoordinateExtent>(infiniteExtent),
|
||||
translateExtent: writable<CoordinateExtent>(infiniteExtent),
|
||||
autoPanOnNodeDrag: writable<boolean>(true),
|
||||
@@ -136,6 +145,9 @@ export const getInitialStore = ({
|
||||
onlyRenderVisibleElements: writable<boolean>(false),
|
||||
onerror: writable<OnError>(devWarn),
|
||||
ondelete: writable<OnDelete>(undefined),
|
||||
onedgecreate: writable<OnEdgeCreate>(undefined)
|
||||
onedgecreate: writable<OnEdgeCreate>(undefined),
|
||||
onconnect: writable<OnConnect>(undefined),
|
||||
onconnectstart: writable<OnConnectStart>(undefined),
|
||||
onconnectend: writable<OnConnectEnd>(undefined)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
import {
|
||||
writable,
|
||||
get,
|
||||
type Unsubscriber,
|
||||
type Subscriber,
|
||||
type Updater,
|
||||
type Writable,
|
||||
get
|
||||
type Writable
|
||||
} from 'svelte/store';
|
||||
import { updateNodes, type Viewport, type PanZoomInstance } from '@xyflow/system';
|
||||
import {
|
||||
adoptUserProvidedNodes,
|
||||
updateConnectionLookup,
|
||||
type Viewport,
|
||||
type PanZoomInstance,
|
||||
type ConnectionLookup,
|
||||
type EdgeLookup,
|
||||
type NodeLookup
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type { DefaultEdgeOptions, DefaultNodeOptions, Edge, Node } from '$lib/types';
|
||||
|
||||
@@ -119,7 +127,7 @@ export type NodeStoreOptions = {
|
||||
// The user only passes in relative positions, so we need to calculate the absolute positions based on the parent nodes.
|
||||
export const createNodesStore = (
|
||||
nodes: Node[],
|
||||
nodeLookup: Map<string, Node>
|
||||
nodeLookup: NodeLookup<Node>
|
||||
): {
|
||||
subscribe: (this: void, run: Subscriber<Node[]>) => Unsubscriber;
|
||||
update: (this: void, updater: Updater<Node[]>) => void;
|
||||
@@ -133,7 +141,7 @@ export const createNodesStore = (
|
||||
let elevateNodesOnSelect = true;
|
||||
|
||||
const _set = (nds: Node[]): Node[] => {
|
||||
const nextNodes = updateNodes(nds, nodeLookup, {
|
||||
const nextNodes = adoptUserProvidedNodes(nds, nodeLookup, {
|
||||
elevateNodesOnSelect,
|
||||
defaults
|
||||
});
|
||||
@@ -168,6 +176,8 @@ export const createNodesStore = (
|
||||
|
||||
export const createEdgesStore = (
|
||||
edges: Edge[],
|
||||
connectionLookup: ConnectionLookup,
|
||||
edgeLookup: EdgeLookup<Edge>,
|
||||
defaultOptions?: DefaultEdgeOptions
|
||||
): Writable<Edge[]> & { setDefaultOptions: (opts: DefaultEdgeOptions) => void } => {
|
||||
const { subscribe, set, update } = writable<Edge[]>([]);
|
||||
@@ -176,6 +186,9 @@ export const createEdgesStore = (
|
||||
|
||||
const _set: typeof set = (eds: Edge[]) => {
|
||||
const nextEdges = defaults ? eds.map((edge) => ({ ...defaults, ...edge })) : eds;
|
||||
|
||||
updateConnectionLookup(connectionLookup, edgeLookup, nextEdges);
|
||||
|
||||
value = nextEdges;
|
||||
set(value);
|
||||
};
|
||||
|
||||
+10
-5
@@ -1,10 +1,10 @@
|
||||
import { derived } from 'svelte/store';
|
||||
import { groupEdgesByZLevel, isEdgeVisible, getEdgePosition } from '@xyflow/system';
|
||||
import { isEdgeVisible, getEdgePosition, getElevatedEdgeZIndex } from '@xyflow/system';
|
||||
|
||||
import type { EdgeLayouted } from '$lib/types';
|
||||
import type { SvelteFlowStoreState } from './types';
|
||||
|
||||
export function getEdgeTree(store: SvelteFlowStoreState) {
|
||||
export function getVisibleEdges(store: SvelteFlowStoreState) {
|
||||
const visibleEdges = derived(
|
||||
[
|
||||
store.edges,
|
||||
@@ -64,6 +64,13 @@ export function getEdgeTree(store: SvelteFlowStoreState) {
|
||||
if (edgePosition) {
|
||||
res.push({
|
||||
...edge,
|
||||
zIndex: getElevatedEdgeZIndex({
|
||||
selected: edge.selected,
|
||||
zIndex: edge.zIndex,
|
||||
sourceNode,
|
||||
targetNode,
|
||||
elevateOnSelect: false
|
||||
}),
|
||||
...edgePosition
|
||||
});
|
||||
}
|
||||
@@ -71,9 +78,7 @@ export function getEdgeTree(store: SvelteFlowStoreState) {
|
||||
return res;
|
||||
}, []);
|
||||
|
||||
const groupedEdges = groupEdgesByZLevel<EdgeLayouted>(layoutedEdges, nodeLookup, false);
|
||||
|
||||
return groupedEdges;
|
||||
return layoutedEdges;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export type StraightEdgeProps = Omit<EdgeComponentProps, 'sourcePosition' | 'tar
|
||||
|
||||
export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>;
|
||||
|
||||
export type DefaultEdgeOptions = Omit<DefaultEdgeOptionsBase<Edge>, 'focusable'>;
|
||||
export type DefaultEdgeOptions = DefaultEdgeOptionsBase<Edge>;
|
||||
|
||||
export type EdgeLayouted = Pick<
|
||||
Edge,
|
||||
@@ -121,6 +121,7 @@ export type EdgeLayouted = Pick<
|
||||
| 'ariaLabel'
|
||||
| 'hidden'
|
||||
| 'class'
|
||||
| 'zIndex'
|
||||
> &
|
||||
EdgePosition & {
|
||||
sourceNode?: Node;
|
||||
|
||||
@@ -31,6 +31,8 @@ export type HandleComponentProps = {
|
||||
isConnectable?: boolean;
|
||||
isConnectableStart?: boolean;
|
||||
isConnectableEnd?: boolean;
|
||||
onconnect?: (connections: Connection[]) => void;
|
||||
ondisconnect?: (connections: Connection[]) => void;
|
||||
};
|
||||
|
||||
export type FitViewOptions = FitViewOptionsBase<Node>;
|
||||
|
||||
@@ -17,7 +17,7 @@ import type { Edge, Node } from '$lib/types';
|
||||
* @param element - The element to test
|
||||
* @returns A boolean indicating whether the element is an Node
|
||||
*/
|
||||
export const isNode = isNodeBase<Node, Edge>;
|
||||
export const isNode = isNodeBase<Node>;
|
||||
|
||||
/**
|
||||
* Test whether an object is useable as an Edge
|
||||
@@ -26,7 +26,7 @@ export const isNode = isNodeBase<Node, Edge>;
|
||||
* @param element - The element to test
|
||||
* @returns A boolean indicating whether the element is an Edge
|
||||
*/
|
||||
export const isEdge = isEdgeBase<Node, Edge>;
|
||||
export const isEdge = isEdgeBase<Edge>;
|
||||
|
||||
/**
|
||||
* Pass in a node, and get connected nodes where edge.source === node.id
|
||||
|
||||
Reference in New Issue
Block a user