@@ -3,6 +3,7 @@ import DragHandleNode from './components/DragHandleNode.svelte';
|
||||
export default {
|
||||
flowProps: {
|
||||
fitView: true,
|
||||
nodeDragThreshold: 0,
|
||||
nodeTypes: {
|
||||
DragHandleNode
|
||||
},
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let isConnectable: $$Props['isConnectable'];
|
||||
export let isConnectable: $$Props['isConnectable'];
|
||||
$$restProps;
|
||||
|
||||
const DEFAULT_HANDLE_STYLE = 'width: 10px; height: 10px; bottom: -5px;';
|
||||
const handleStyle = 'width: 10px; height: 10px; bottom: -5px;';
|
||||
</script>
|
||||
|
||||
<div style="background: #DDD; padding: 25px">
|
||||
<div>Node</div>
|
||||
<Handle
|
||||
type="source"
|
||||
id="red"
|
||||
position={Position.Bottom}
|
||||
style={DEFAULT_HANDLE_STYLE + 'left: 15%; background: red;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
id="blue"
|
||||
style={DEFAULT_HANDLE_STYLE + 'left: 50%; background: blue;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
id="orange"
|
||||
style={DEFAULT_HANDLE_STYLE + 'left: 85%; background: orange;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
<div>Node</div>
|
||||
<Handle
|
||||
type="source"
|
||||
id="red"
|
||||
position={Position.Bottom}
|
||||
style={handleStyle + 'left: 15%; background: red;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
id="blue"
|
||||
style={handleStyle + 'left: 50%; background: blue;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
<Handle
|
||||
type="source"
|
||||
position={Position.Bottom}
|
||||
id="orange"
|
||||
style={handleStyle + 'left: 85%; background: orange;'}
|
||||
{isConnectable}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
export let data: $$Props['data'];
|
||||
|
||||
$$restProps;
|
||||
|
||||
const { colorStore } = data;
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,27 +4,18 @@
|
||||
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;
|
||||
|
||||
$$restProps;
|
||||
|
||||
$: [edgePath, labelX, labelY] = getBezierPath({
|
||||
sourceX,
|
||||
@@ -34,18 +25,6 @@
|
||||
targetY,
|
||||
targetPosition
|
||||
});
|
||||
|
||||
source;
|
||||
target;
|
||||
animated;
|
||||
selected;
|
||||
data;
|
||||
label;
|
||||
labelStyle;
|
||||
markerStart;
|
||||
interactionWidth;
|
||||
sourceHandleId;
|
||||
targetHandleId;
|
||||
</script>
|
||||
|
||||
<BaseEdge path={edgePath} {markerEnd} {style} />
|
||||
|
||||
@@ -3,14 +3,8 @@
|
||||
|
||||
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;
|
||||
@@ -19,23 +13,12 @@
|
||||
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;
|
||||
$$restProps;
|
||||
</script>
|
||||
|
||||
<BezierEdge
|
||||
|
||||
@@ -33,33 +33,7 @@
|
||||
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 positionAbsoluteX: $$Props['positionAbsoluteX'] = 0;
|
||||
export let positionAbsoluteY: $$Props['positionAbsoluteY'] = 0;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
|
||||
data;
|
||||
targetPosition;
|
||||
sourcePosition;
|
||||
width;
|
||||
height;
|
||||
selected;
|
||||
type;
|
||||
zIndex;
|
||||
dragging;
|
||||
dragHandle;
|
||||
positionAbsoluteX;
|
||||
positionAbsoluteY;
|
||||
isConnectable;
|
||||
$$restProps;
|
||||
</script>
|
||||
|
||||
<div class="custom">
|
||||
|
||||
@@ -21,34 +21,7 @@
|
||||
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;
|
||||
$$restProps;
|
||||
</script>
|
||||
|
||||
<div class="custom">
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { SvelteFlow, Controls, Panel, type Node, type Edge } from '@xyflow/svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { SvelteFlow, Controls, Panel, type Edge } from '@xyflow/svelte';
|
||||
|
||||
import DefaultResizer from './DefaultResizer.svelte';
|
||||
import CustomResizer from './CustomResizer.svelte';
|
||||
import VerticalResizer from './VerticalResizer.svelte';
|
||||
import HorizontalResizer from './HorizontalResizer.svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
import '@xyflow/svelte/dist/style.css';
|
||||
import type { ResizeNode } from './types';
|
||||
|
||||
const nodeTypes = {
|
||||
defaultResizer: DefaultResizer,
|
||||
@@ -20,7 +21,7 @@
|
||||
|
||||
const edges = writable<Edge[]>([]);
|
||||
|
||||
const nodes = writable<Node[]>([
|
||||
const nodes = writable<ResizeNode[]>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'defaultResizer',
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps, NodeResizeControl } from '@xyflow/svelte';
|
||||
import type { ResizeNode } from './types';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<ResizeNode>;
|
||||
|
||||
export let data: $$Props['data'] = undefined;
|
||||
export let data: $$Props['data'];
|
||||
</script>
|
||||
|
||||
<NodeResizeControl
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { Handle, NodeResizer, Position, type NodeProps } from '@xyflow/svelte';
|
||||
import type { ResizeNode } from './types';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<ResizeNode>;
|
||||
|
||||
export let data: $$Props['data'] = undefined;
|
||||
export let data: $$Props['data'];
|
||||
export let selected: $$Props['selected'] = undefined;
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
||||
import type { ResizeNode } from './types';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<ResizeNode>;
|
||||
|
||||
export let data: $$Props['data'] = undefined;
|
||||
export let data: $$Props['data'];
|
||||
</script>
|
||||
|
||||
<NodeResizeControl
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
function ResizeIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="8"
|
||||
height="8"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
style={{ position: 'absolute', right: 2, bottom: 2 }}
|
||||
>
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<polyline points="16 20 20 20 20 16" />
|
||||
<line x1="14" y1="14" x2="20" y2="20" />
|
||||
<polyline points="8 4 4 4 4 8" />
|
||||
<line x1="4" y1="4" x2="10" y2="10" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default ResizeIcon;
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { Handle, NodeResizeControl, Position, type NodeProps } from '@xyflow/svelte';
|
||||
import type { ResizeNode } from './types';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<ResizeNode>;
|
||||
|
||||
export let data: $$Props['data'] = undefined;
|
||||
export let data: $$Props['data'];
|
||||
</script>
|
||||
|
||||
<NodeResizeControl
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
type Node,
|
||||
type ShouldResize,
|
||||
type OnResizeStart,
|
||||
type OnResize,
|
||||
type OnResizeEnd
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
export type ResizeNode = Node<{
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
minHeight?: number;
|
||||
maxHeight?: number;
|
||||
shouldResize?: ShouldResize;
|
||||
onResizeStart?: OnResizeStart;
|
||||
onResize?: OnResize;
|
||||
onResizeEnd?: OnResizeEnd;
|
||||
keepAspectRatio?: boolean;
|
||||
label?: string;
|
||||
isVisible?: boolean;
|
||||
}>;
|
||||
@@ -2,6 +2,7 @@
|
||||
import { NodeToolbar, type NodeProps, Handle, Position } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
$$restProps;
|
||||
|
||||
export let data: $$Props['data'];
|
||||
</script>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
type Node,
|
||||
type Edge,
|
||||
ConnectionMode,
|
||||
useSvelteFlow,
|
||||
ControlButton
|
||||
ControlButton,
|
||||
type FitViewOptions
|
||||
} from '@xyflow/svelte';
|
||||
|
||||
import CustomNode from './CustomNode.svelte';
|
||||
@@ -33,6 +33,11 @@
|
||||
custom: CustomEdge
|
||||
};
|
||||
|
||||
const fitViewOptions: FitViewOptions = {
|
||||
padding: 0.2,
|
||||
nodes: [{ id: '1' }, { id: '2' }]
|
||||
};
|
||||
|
||||
const nodes = writable<Node[]>([
|
||||
{
|
||||
id: '1',
|
||||
@@ -191,7 +196,7 @@
|
||||
attributionPosition={'top-center'}
|
||||
deleteKey={['Backspace', 'd']}
|
||||
>
|
||||
<Controls orientation="horizontal">
|
||||
<Controls orientation="horizontal" {fitViewOptions}>
|
||||
<ControlButton slot="before">xy</ControlButton>
|
||||
<ControlButton aria-label="log" on:click={() => console.log('control button')}
|
||||
>log</ControlButton
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
import { Handle, Position, type BuiltInNode, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<BuiltInNode>;
|
||||
$$restProps;
|
||||
|
||||
export let data: { label: string } = { label: 'Node' };
|
||||
export let positionAbsoluteX: number = 0;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { NodeProps } from '@xyflow/svelte';
|
||||
import type { BuiltInNode, NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
type $$Props = NodeProps<BuiltInNode>;
|
||||
$$restProps;
|
||||
|
||||
export let data: { label: string } = { label: 'Node' };
|
||||
</script>
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<script lang="ts">
|
||||
import { Handle, Position, type NodeProps, type XYPosition } from '@xyflow/svelte';
|
||||
import { Handle, Position, type NodeProps } from '@xyflow/svelte';
|
||||
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let id: string;
|
||||
export let positionAbsolute: XYPosition = { x: 0, y: 0 };
|
||||
export let positionAbsoluteX: number = 0;
|
||||
export let positionAbsoluteY: number = 0;
|
||||
export let zIndex: number = 0;
|
||||
|
||||
$$restProps;
|
||||
</script>
|
||||
|
||||
<Handle type="target" position={Position.Top} />
|
||||
<div>{id}</div>
|
||||
<div>
|
||||
x:{Math.round(positionAbsolute.x)} y:{Math.round(positionAbsolute.y)} z:{zIndex}
|
||||
x:{Math.round(positionAbsoluteX)} y:{Math.round(positionAbsoluteY)} z:{zIndex}
|
||||
</div>
|
||||
<Handle type="source" position={Position.Bottom} />
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
type $$Props = NodeProps;
|
||||
|
||||
export let id: $$Props['id'];
|
||||
$$restProps;
|
||||
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@
|
||||
|
||||
$: edgeType = type || 'default';
|
||||
$: edgeComponent = $edgeTypes[edgeType] || BezierEdgeInternal;
|
||||
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
|
||||
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
|
||||
$: markerStartUrl = markerStart ? `url('#${getMarkerId(markerStart, $flowId)}')` : undefined;
|
||||
$: markerEndUrl = markerEnd ? `url('#${getMarkerId(markerEnd, $flowId)}')` : undefined;
|
||||
$: isSelectable = selectable || ($elementsSelectable && typeof selectable === 'undefined');
|
||||
|
||||
const handleEdgeSelect = useHandleEdgeSelect();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
export let position: $$Props['position'] = Position.Top;
|
||||
export let style: $$Props['style'] = undefined;
|
||||
export let isConnectable: $$Props['isConnectable'] = undefined;
|
||||
export let isValidConnection: $$Props['isValidConnection'] = undefined;
|
||||
export let onconnect: $$Props['onconnect'] = undefined;
|
||||
export let ondisconnect: $$Props['ondisconnect'] = undefined;
|
||||
// @todo implement connectablestart, connectableend
|
||||
@@ -31,12 +32,12 @@
|
||||
let className: $$Props['class'] = undefined;
|
||||
export { className as class };
|
||||
|
||||
const isTarget = type === 'target';
|
||||
$: isTarget = type === 'target';
|
||||
const nodeId = getContext<string>('svelteflow__node_id');
|
||||
const connectable = getContext<Writable<boolean>>('svelteflow__node_connectable');
|
||||
$: isConnectable = isConnectable !== undefined ? isConnectable : $connectable;
|
||||
|
||||
const handleId = id || null;
|
||||
$: handleId = id || null;
|
||||
|
||||
const store = useStore();
|
||||
const {
|
||||
@@ -45,7 +46,7 @@
|
||||
nodeLookup,
|
||||
connectionRadius,
|
||||
viewport,
|
||||
isValidConnection,
|
||||
isValidConnection: isValidConnectionStore,
|
||||
lib,
|
||||
addEdge,
|
||||
onedgecreate,
|
||||
@@ -77,7 +78,7 @@
|
||||
lib: $lib,
|
||||
autoPanOnConnect: $autoPanOnConnect,
|
||||
flowId: $flowId,
|
||||
isValidConnection: $isValidConnection,
|
||||
isValidConnection: isValidConnection ?? $isValidConnectionStore,
|
||||
updateConnection,
|
||||
cancelConnection,
|
||||
panBy,
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
import { useStore } from '$lib/store';
|
||||
import { Selection } from '$lib/components/Selection';
|
||||
import drag from '$lib/actions/drag';
|
||||
import type { Node } from '$lib/types';
|
||||
import { createNodeEventDispatcher } from '$lib';
|
||||
import type { Node, NodeEventMap } from '$lib/types';
|
||||
|
||||
const store = useStore();
|
||||
const { selectionRectMode, nodes } = store;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
}>();
|
||||
const dispatchNodeEvent = createNodeEventDispatcher();
|
||||
const dispatch = createEventDispatcher<
|
||||
NodeEventMap & {
|
||||
selectioncontextmenu: { nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
selectionclick: { nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
}
|
||||
>();
|
||||
|
||||
$: selectedNodes = $nodes.filter((n) => n.selected);
|
||||
$: bounds = getNodesBounds(selectedNodes);
|
||||
@@ -37,13 +37,13 @@
|
||||
disabled: false,
|
||||
store,
|
||||
onDrag: (event, _, __, nodes) => {
|
||||
dispatchNodeEvent('nodedrag', { event, targetNode: null, nodes });
|
||||
dispatch('nodedrag', { event, targetNode: null, nodes });
|
||||
},
|
||||
onDragStart: (event, _, __, nodes) => {
|
||||
dispatchNodeEvent('nodedragstart', { event, targetNode: null, nodes });
|
||||
dispatch('nodedragstart', { event, targetNode: null, nodes });
|
||||
},
|
||||
onDragStop: (event, _, __, nodes) => {
|
||||
dispatchNodeEvent('nodedragstop', { event, targetNode: null, nodes });
|
||||
dispatch('nodedragstop', { event, targetNode: null, nodes });
|
||||
}
|
||||
}}
|
||||
on:contextmenu={onContextMenu}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<svelte:options immutable />
|
||||
|
||||
<script lang="ts">
|
||||
import { setContext, onDestroy } from 'svelte';
|
||||
import { setContext, onDestroy, createEventDispatcher } from 'svelte';
|
||||
import { get, writable } from 'svelte/store';
|
||||
import cc from 'classcat';
|
||||
import { errorMessages, Position } from '@xyflow/system';
|
||||
@@ -11,7 +11,7 @@
|
||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||
import type { NodeWrapperProps } from './types';
|
||||
import { getNodeInlineStyleDimensions } from './utils';
|
||||
import { createNodeEventDispatcher } from '$lib';
|
||||
import type { NodeEventMap } from '$lib/types';
|
||||
|
||||
interface $$Props extends NodeWrapperProps {}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
let nodeRef: HTMLDivElement;
|
||||
let prevNodeRef: HTMLDivElement | null = null;
|
||||
|
||||
const dispatchNodeEvent = createNodeEventDispatcher();
|
||||
const dispatchNodeEvent = createEventDispatcher<NodeEventMap>();
|
||||
const connectableStore = writable(connectable);
|
||||
let prevType: string | undefined = undefined;
|
||||
let prevSourcePosition: Position | undefined = undefined;
|
||||
@@ -104,7 +104,7 @@
|
||||
{
|
||||
id,
|
||||
nodeElement: nodeRef,
|
||||
forceUpdate: true
|
||||
force: true
|
||||
}
|
||||
]
|
||||
])
|
||||
@@ -141,7 +141,7 @@
|
||||
handleNodeSelection(id);
|
||||
}
|
||||
|
||||
dispatchNodeEvent('nodeclick', { node, event });
|
||||
dispatchNodeEvent('nodeclick', { node: node.internals.userNode, event });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Node } from '$lib/types';
|
||||
import type { InternalNode, Node } from '$lib/types';
|
||||
|
||||
export type NodeWrapperProps = Pick<
|
||||
Node,
|
||||
@@ -32,6 +32,6 @@ export type NodeWrapperProps = Pick<
|
||||
resizeObserver?: ResizeObserver | null;
|
||||
isParent?: boolean;
|
||||
zIndex: number;
|
||||
node: Node;
|
||||
node: InternalNode;
|
||||
initialized: boolean;
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
updates.set(id, {
|
||||
id,
|
||||
nodeElement: entry.target as HTMLDivElement,
|
||||
forceUpdate: true
|
||||
force: true
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { Node, Edge } from '$lib/types';
|
||||
import type { Node, Edge, InternalNode } from '$lib/types';
|
||||
import type { PaneProps } from './types';
|
||||
|
||||
type $$Props = PaneProps;
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
let container: HTMLDivElement;
|
||||
let containerBounds: DOMRect | null = null;
|
||||
let selectedNodes: Node[] = [];
|
||||
let selectedNodes: InternalNode[] = [];
|
||||
|
||||
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
|
||||
$: isSelecting =
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { derived, type Readable } from 'svelte/store';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { InternalNode } from '$lib/types';
|
||||
|
||||
/**
|
||||
* Hook to get an internal node by id.
|
||||
*
|
||||
* @public
|
||||
* @param id - the node id
|
||||
* @returns a readable with an internal node or undefined
|
||||
*/
|
||||
export function useInternalNode(id: string): Readable<InternalNode | undefined> {
|
||||
const { nodeLookup, nodes } = useStore();
|
||||
|
||||
return derived([nodeLookup, nodes], ([nodeLookup]) => nodeLookup.get(id));
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from '@xyflow/system';
|
||||
|
||||
import { useStore } from '$lib/store';
|
||||
import type { Edge, FitViewOptions, Node } from '$lib/types';
|
||||
import type { Edge, FitViewOptions, InternalNode, Node } from '$lib/types';
|
||||
import { isNode } from '$lib/utils';
|
||||
|
||||
/**
|
||||
@@ -41,6 +41,13 @@ export function useSvelteFlow(): {
|
||||
* @param options.duration - optional duration. If set, a transition will be applied
|
||||
*/
|
||||
zoomOut: ZoomInOut;
|
||||
/**
|
||||
* Returns an internal node by id.
|
||||
*
|
||||
* @param id - the node id
|
||||
* @returns the node or undefined if no node was found
|
||||
*/
|
||||
getInternalNode: (id: string) => InternalNode | undefined;
|
||||
/**
|
||||
* Returns a node by id.
|
||||
*
|
||||
@@ -280,10 +287,13 @@ export function useSvelteFlow(): {
|
||||
}
|
||||
};
|
||||
|
||||
const getInternalNode = (id: string) => get(nodeLookup).get(id);
|
||||
|
||||
return {
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
getNode: (id) => get(nodeLookup).get(id),
|
||||
getInternalNode,
|
||||
getNode: (id) => getInternalNode(id)?.internals.userNode,
|
||||
getNodes: (ids) => (ids === undefined ? get(nodes) : getElements(get(nodeLookup), ids)),
|
||||
getEdge: (id) => get(edgeLookup).get(id),
|
||||
getEdges: (ids) => (ids === undefined ? get(edges) : getElements(get(edgeLookup), ids)),
|
||||
@@ -474,14 +484,17 @@ export function useSvelteFlow(): {
|
||||
viewport
|
||||
};
|
||||
}
|
||||
|
||||
function getElements<EdgeOrNode>(lookup: Map<string, EdgeOrNode>, ids: string[]) {
|
||||
function getElements(lookup: Map<string, InternalNode>, ids: string[]): Node[];
|
||||
function getElements(lookup: Map<string, Edge>, ids: string[]): Edge[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function getElements(lookup: Map<string, any>, ids: string[]): any[] {
|
||||
const result = [];
|
||||
|
||||
for (const id of ids) {
|
||||
const element = lookup.get(id);
|
||||
const item = lookup.get(id);
|
||||
|
||||
if (element) {
|
||||
if (item) {
|
||||
const element = 'internals' in item ? item.internals?.userNode : item;
|
||||
result.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export function useUpdateNodeInternals(): UpdateNodeInternals {
|
||||
) as HTMLDivElement;
|
||||
|
||||
if (nodeElement) {
|
||||
updates.set(updateId, { id: updateId, nodeElement, forceUpdate: true });
|
||||
updates.set(updateId, { id: updateId, nodeElement, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
export let ariaLabel: $$Props['aria-label'] = undefined;
|
||||
export let style: $$Props['style'] = undefined;
|
||||
export let orientation: $$Props['orientation'] = 'vertical';
|
||||
export let fitViewOptions: $$Props['fitViewOptions'] = undefined;
|
||||
|
||||
let className: $$Props['class'] = '';
|
||||
export { className as class };
|
||||
@@ -63,7 +64,7 @@
|
||||
};
|
||||
|
||||
const onFitViewHandler = () => {
|
||||
fitView();
|
||||
fitView(fitViewOptions);
|
||||
};
|
||||
|
||||
const onToggleInteractivity = () => {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { HTMLButtonAttributes } from 'svelte/elements';
|
||||
import type { PanelPosition } from '@xyflow/system';
|
||||
|
||||
import type { FitViewOptions } from '$lib/types';
|
||||
|
||||
export type ControlsProps = {
|
||||
/** Position of the controls on the pane
|
||||
* @example PanelPosition.TopLeft, PanelPosition.TopRight,
|
||||
@@ -21,6 +23,7 @@ export type ControlsProps = {
|
||||
style?: string;
|
||||
class?: string;
|
||||
orientation?: 'horizontal' | 'vertical';
|
||||
fitViewOptions?: FitViewOptions;
|
||||
};
|
||||
|
||||
export type ControlButtonProps = HTMLButtonAttributes & {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { getContext, setContext } from 'svelte';
|
||||
import { derived, get, writable } from 'svelte/store';
|
||||
import {
|
||||
createMarkerIds,
|
||||
fitView as fitViewUtil,
|
||||
fitView as fitViewSystem,
|
||||
getElementsToRemove,
|
||||
panBy as panBySystem,
|
||||
updateNodeInternals as updateNodeInternalsSystem,
|
||||
@@ -111,8 +111,12 @@ export function createStore({
|
||||
switch (change.type) {
|
||||
case 'dimensions': {
|
||||
const measured = { ...node.measured, ...change.dimensions };
|
||||
node.width = change.dimensions?.width ?? node.width;
|
||||
node.height = change.dimensions?.height ?? node.height;
|
||||
|
||||
if (change.setAttributes) {
|
||||
node.width = change.dimensions?.width ?? node.width;
|
||||
node.height = change.dimensions?.height ?? node.height;
|
||||
}
|
||||
|
||||
node.measured = measured;
|
||||
break;
|
||||
}
|
||||
@@ -136,7 +140,7 @@ export function createStore({
|
||||
return false;
|
||||
}
|
||||
|
||||
return fitViewUtil(
|
||||
return fitViewSystem(
|
||||
{
|
||||
nodeLookup: get(store.nodeLookup),
|
||||
width: get(store.width),
|
||||
@@ -350,8 +354,6 @@ export function createStore({
|
||||
store.selectionRectMode.set(null);
|
||||
store.snapGrid.set(null);
|
||||
store.isValidConnection.set(() => true);
|
||||
store.nodes.set([]);
|
||||
store.edges.set([]);
|
||||
|
||||
unselectNodesAndEdges();
|
||||
cancelConnection();
|
||||
|
||||
@@ -45,11 +45,15 @@ export type HandleComponentProps = {
|
||||
isConnectableStart?: boolean;
|
||||
/** Should you be able to connect to this handle */
|
||||
isConnectableEnd?: boolean;
|
||||
/** Function that is called when checking if connection is valid.
|
||||
* Overrides the isValidConnection on the Flow component.
|
||||
*/
|
||||
isValidConnection?: IsValidConnection;
|
||||
onconnect?: (connections: Connection[]) => void;
|
||||
ondisconnect?: (connections: Connection[]) => void;
|
||||
};
|
||||
|
||||
export type FitViewOptions = FitViewOptionsBase<Node>;
|
||||
export type FitViewOptions<NodeType extends Node = Node> = FitViewOptionsBase<NodeType>;
|
||||
|
||||
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;
|
||||
export type OnEdgeCreate = (connection: Connection) => Edge | Connection | void;
|
||||
|
||||
@@ -45,3 +45,14 @@ export type NodeTypes = Record<
|
||||
export type DefaultNodeOptions = Partial<Omit<Node, 'id'>>;
|
||||
|
||||
export type BuiltInNode = Node<{ label: string }, 'input' | 'output' | 'default'>;
|
||||
|
||||
export type NodeEventMap = {
|
||||
nodeclick: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodedrag: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodedragstart: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodedragstop: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodemouseenter: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodemouseleave: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodemousemove: { node: Node; event: MouseEvent | TouchEvent };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { isNodeBase, isEdgeBase } from '@xyflow/system';
|
||||
|
||||
import type { Edge, Node } from '$lib/types';
|
||||
@@ -22,15 +21,3 @@ export const isNode = <NodeType extends Node = Node>(element: unknown): element
|
||||
*/
|
||||
export const isEdge = <EdgeType extends Edge = Edge>(element: unknown): element is EdgeType =>
|
||||
isEdgeBase<EdgeType>(element);
|
||||
|
||||
export const createNodeEventDispatcher = () =>
|
||||
createEventDispatcher<{
|
||||
nodeclick: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodecontextmenu: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodedrag: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodedragstart: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodedragstop: { targetNode: Node | null; nodes: Node[]; event: MouseEvent | TouchEvent };
|
||||
nodemouseenter: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodemouseleave: { node: Node; event: MouseEvent | TouchEvent };
|
||||
nodemousemove: { node: Node; event: MouseEvent | TouchEvent };
|
||||
}>();
|
||||
|
||||
@@ -61,13 +61,13 @@ export type FitViewParamsBase<NodeType extends NodeBase> = {
|
||||
nodeOrigin?: NodeOrigin;
|
||||
};
|
||||
|
||||
export type FitViewOptionsBase<NodeType extends NodeBase> = {
|
||||
export type FitViewOptionsBase<NodeType extends NodeBase = NodeBase> = {
|
||||
padding?: number;
|
||||
includeHiddenNodes?: boolean;
|
||||
minZoom?: number;
|
||||
maxZoom?: number;
|
||||
duration?: number;
|
||||
nodes?: (NodeType | { id: NodeType['id'] })[];
|
||||
nodes?: (NodeType | { id: string })[];
|
||||
};
|
||||
|
||||
export type Viewport = {
|
||||
|
||||
Reference in New Issue
Block a user