fixed subflows, cleaned up nodeRenderer, cleaned up nodewrapper
This commit is contained in:
@@ -1,45 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { setContext, onDestroy } from 'svelte';
|
||||
import cc from 'classcat';
|
||||
import { errorMessages, Position } from '@xyflow/system';
|
||||
import { errorMessages, nodeHasDimensions, Position } from '@xyflow/system';
|
||||
|
||||
import drag from '$lib/actions/drag';
|
||||
import DefaultNode from '$lib/components/nodes/DefaultNode.svelte';
|
||||
import type { ConnectableContext, NodeWrapperProps } from './types';
|
||||
import { getNodeInlineStyleDimensions } from './utils';
|
||||
import type { NodeEvents } from '$lib/types';
|
||||
import type { Node, NodeEvents } from '$lib/types';
|
||||
|
||||
let {
|
||||
store,
|
||||
node,
|
||||
id,
|
||||
data = {},
|
||||
selected = false,
|
||||
draggable,
|
||||
selectable,
|
||||
deletable,
|
||||
connectable = true,
|
||||
hidden = false,
|
||||
dragging = false,
|
||||
resizeObserver = null,
|
||||
style,
|
||||
class: className,
|
||||
type = 'default',
|
||||
isParent = false,
|
||||
parentId,
|
||||
positionX,
|
||||
positionY,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
zIndex,
|
||||
measuredWidth,
|
||||
measuredHeight,
|
||||
initialWidth,
|
||||
initialHeight,
|
||||
width,
|
||||
height,
|
||||
dragHandle,
|
||||
initialized = false,
|
||||
resizeObserver,
|
||||
nodeClickDistance,
|
||||
onnodeclick,
|
||||
onnodedrag,
|
||||
@@ -51,6 +24,58 @@
|
||||
onnodecontextmenu
|
||||
}: NodeWrapperProps & NodeEvents = $props();
|
||||
|
||||
let {
|
||||
id,
|
||||
data = {},
|
||||
selected = false,
|
||||
draggable: _draggable,
|
||||
selectable: _selectable,
|
||||
deletable = true,
|
||||
connectable: _connectable,
|
||||
hidden = false,
|
||||
dragging = false,
|
||||
style,
|
||||
class: className,
|
||||
type = 'default',
|
||||
parentId,
|
||||
sourcePosition,
|
||||
targetPosition,
|
||||
measured: { width: measuredWidth, height: measuredHeight } = { width: 0, height: 0 },
|
||||
initialWidth,
|
||||
initialHeight,
|
||||
width,
|
||||
height,
|
||||
dragHandle
|
||||
} = $derived(node);
|
||||
|
||||
let draggable = $derived(_draggable ?? store.nodesDraggable);
|
||||
let selectable = $derived(_selectable ?? store.elementsSelectable);
|
||||
let connectable = $derived(_connectable ?? store.nodesConnectable);
|
||||
let initialized = $derived(nodeHasDimensions(node));
|
||||
|
||||
// TODO: does this make sense
|
||||
let flipFlop = false;
|
||||
let shouldRerenderSignal = $derived.by(() =>
|
||||
store.adoptNodes.has(id) ? (flipFlop = !flipFlop) : flipFlop
|
||||
);
|
||||
|
||||
function getInternalNode(node: Node, shouldRerender: boolean = false) {
|
||||
return { ...store.nodeLookup.get(node.id)! };
|
||||
}
|
||||
|
||||
let {
|
||||
internals: {
|
||||
z: zIndex = 0,
|
||||
positionAbsolute: { x: positionX, y: positionY }
|
||||
}
|
||||
} = $derived(getInternalNode(node, shouldRerenderSignal));
|
||||
|
||||
function isInParentLookup(id: string) {
|
||||
return store.parentLookup.has(id);
|
||||
}
|
||||
|
||||
let isParent = $derived(isInParentLookup(id));
|
||||
|
||||
let nodeRef: HTMLDivElement | null = $state(null);
|
||||
let prevNodeRef: HTMLDivElement | null = null;
|
||||
|
||||
@@ -144,7 +169,7 @@
|
||||
store.handleNodeSelection(id);
|
||||
}
|
||||
|
||||
onnodeclick?.({ node: node.internals.userNode, event });
|
||||
onnodeclick?.({ node, event });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,40 +5,41 @@ export type ConnectableContext = {
|
||||
value: boolean;
|
||||
};
|
||||
|
||||
export type NodeWrapperProps = Pick<
|
||||
Node,
|
||||
| 'id'
|
||||
| 'class'
|
||||
| 'connectable'
|
||||
| 'data'
|
||||
| 'draggable'
|
||||
| 'dragging'
|
||||
| 'selected'
|
||||
| 'selectable'
|
||||
| 'deletable'
|
||||
| 'style'
|
||||
| 'type'
|
||||
| 'sourcePosition'
|
||||
| 'targetPosition'
|
||||
| 'dragHandle'
|
||||
| 'hidden'
|
||||
| 'width'
|
||||
| 'height'
|
||||
| 'initialWidth'
|
||||
| 'initialHeight'
|
||||
| 'parentId'
|
||||
> & {
|
||||
measuredWidth?: number;
|
||||
measuredHeight?: number;
|
||||
type: string;
|
||||
positionX: number;
|
||||
positionY: number;
|
||||
'on:nodeclick'?: (event: MouseEvent) => void;
|
||||
resizeObserver?: ResizeObserver | null;
|
||||
isParent?: boolean;
|
||||
zIndex: number;
|
||||
node: InternalNode;
|
||||
initialized: boolean;
|
||||
export type NodeWrapperProps = {
|
||||
// Pick<
|
||||
// Node,
|
||||
// | 'id'
|
||||
// | 'class'
|
||||
// | 'connectable'
|
||||
// | 'data'
|
||||
// | 'draggable'
|
||||
// | 'dragging'
|
||||
// | 'selected'
|
||||
// | 'selectable'
|
||||
// | 'deletable'
|
||||
// | 'style'
|
||||
// | 'type'
|
||||
// | 'sourcePosition'
|
||||
// | 'targetPosition'
|
||||
// | 'dragHandle'
|
||||
// | 'hidden'
|
||||
// | 'width'
|
||||
// | 'height'
|
||||
// | 'initialWidth'
|
||||
// | 'initialHeight'
|
||||
// | 'parentId'
|
||||
// > & {
|
||||
// measuredWidth?: number;
|
||||
// measuredHeight?: number;
|
||||
// type: string;
|
||||
// positionX: number;
|
||||
// positionY: number;
|
||||
// 'on:nodeclick'?: (event: MouseEvent) => void;
|
||||
// isParent?: boolean;
|
||||
// zIndex: number;
|
||||
// initialized: boolean;
|
||||
node: Node;
|
||||
nodeClickDistance?: number;
|
||||
resizeObserver?: ResizeObserver | null;
|
||||
store: SvelteFlowStore;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte';
|
||||
import { nodeHasDimensions } from '@xyflow/system';
|
||||
|
||||
import type { Node, NodeEvents } from '$lib/types';
|
||||
import { NodeWrapper } from '$lib/components/NodeWrapper';
|
||||
import type { NodeEvents } from '$lib/types';
|
||||
import type { SvelteFlowStore } from '$lib/store/types';
|
||||
|
||||
let {
|
||||
@@ -19,8 +18,6 @@
|
||||
onnodedragstop
|
||||
}: { store: SvelteFlowStore; nodeClickDistance?: number } & NodeEvents = $props();
|
||||
|
||||
// const { nodes } = store;
|
||||
|
||||
const resizeObserver: ResizeObserver | null =
|
||||
typeof ResizeObserver === 'undefined'
|
||||
? null
|
||||
@@ -43,59 +40,13 @@
|
||||
onDestroy(() => {
|
||||
resizeObserver?.disconnect();
|
||||
});
|
||||
|
||||
function give(node: Node) {
|
||||
const internalNode = store.nodeLookup.get(node.id);
|
||||
// console.log('this reruns most definitely', internalNode);
|
||||
console.log(internalNode?.position);
|
||||
return internalNode;
|
||||
}
|
||||
|
||||
// $inspect(store.nodes).with(console.trace);
|
||||
</script>
|
||||
|
||||
<div class="svelte-flow__nodes">
|
||||
{#each store.nodes as node (node.id)}
|
||||
{@const internalNode = store.nodeLookup.get(node.id)}
|
||||
<NodeWrapper
|
||||
{store}
|
||||
node={internalNode!}
|
||||
id={node.id}
|
||||
data={node.data}
|
||||
selected={!!node.selected}
|
||||
hidden={!!node.hidden}
|
||||
draggable={!!(
|
||||
node.draggable ||
|
||||
(store.nodesDraggable && typeof node.draggable === 'undefined')
|
||||
)}
|
||||
selectable={!!(
|
||||
node.selectable ||
|
||||
(store.elementsSelectable && typeof node.selectable === 'undefined')
|
||||
)}
|
||||
connectable={!!(
|
||||
node.connectable ||
|
||||
(store.nodesConnectable && typeof node.connectable === 'undefined')
|
||||
)}
|
||||
deletable={node.deletable ?? true}
|
||||
positionX={internalNode!.internals.positionAbsolute.x}
|
||||
positionY={internalNode!.internals.positionAbsolute.y}
|
||||
isParent={store.parentLookup.has(node.id)}
|
||||
style={node.style}
|
||||
class={node.class}
|
||||
type={node.type ?? 'default'}
|
||||
sourcePosition={node.sourcePosition}
|
||||
targetPosition={node.targetPosition}
|
||||
dragging={node.dragging}
|
||||
zIndex={internalNode!.internals.z ?? 0}
|
||||
dragHandle={node.dragHandle}
|
||||
initialized={nodeHasDimensions(node)}
|
||||
width={node.width}
|
||||
height={node.height}
|
||||
initialWidth={node.initialWidth}
|
||||
initialHeight={node.initialHeight}
|
||||
measuredWidth={node.measured?.width ?? 0}
|
||||
measuredHeight={node.measured?.height ?? 0}
|
||||
parentId={node.parentId}
|
||||
{node}
|
||||
{resizeObserver}
|
||||
{nodeClickDistance}
|
||||
{onnodeclick}
|
||||
|
||||
@@ -211,13 +211,11 @@ export function useSvelteFlow(): {
|
||||
// nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
|
||||
// options?: { replace: boolean }
|
||||
// ) => void;
|
||||
updateNode:
|
||||
| ((id: string, nodeUpdate: Node | ((node: Node) => Node), options: { replace: true }) => void)
|
||||
| ((
|
||||
id: string,
|
||||
nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
|
||||
options: { replace: false }
|
||||
) => void);
|
||||
updateNode: (
|
||||
id: string,
|
||||
nodeUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
|
||||
options?: { replace: boolean }
|
||||
) => void;
|
||||
/**
|
||||
* Updates the data attribute of a node.
|
||||
*
|
||||
@@ -248,13 +246,11 @@ export function useSvelteFlow(): {
|
||||
* @example
|
||||
* updateNode('node-1', (node) => ({ position: { x: node.position.x + 10, y: node.position.y } }));
|
||||
*/
|
||||
updateEdge:
|
||||
| ((id: string, edgeUpdate: Edge | ((edge: Edge) => Edge), options: { replace: true }) => void)
|
||||
| ((
|
||||
id: string,
|
||||
edgeUpdate: Partial<Edge> | ((edge: Edge) => Partial<Edge>),
|
||||
options?: { replace: false }
|
||||
) => void);
|
||||
updateEdge: (
|
||||
id: string,
|
||||
edgeUpdate: Partial<Edge> | ((edge: Edge) => Partial<Edge>),
|
||||
options?: { replace: boolean }
|
||||
) => void;
|
||||
toObject: () => { nodes: Node[]; edges: Edge[]; viewport: Viewport };
|
||||
/**
|
||||
* Returns the bounds of the given nodes or node ids.
|
||||
|
||||
@@ -243,6 +243,8 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
|
||||
if (node.selected !== selected) {
|
||||
// we need to mutate the node here in order to have the correct selected state in the drag handler
|
||||
const internalNode = store.nodeLookup.get(node.id);
|
||||
if (internalNode) internalNode.selected = selected;
|
||||
node.selected = selected;
|
||||
return { ...node };
|
||||
}
|
||||
|
||||
@@ -91,14 +91,13 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
connectionLookup: ConnectionLookup = new Map();
|
||||
edgeLookup: EdgeLookup = new Map();
|
||||
|
||||
adoptNodes: true = $derived.by(() => {
|
||||
adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
|
||||
adoptNodes: Set<string> = $derived.by(() => {
|
||||
return adoptUserNodes(signals.nodes, this.nodeLookup, this.parentLookup, {
|
||||
nodeExtent: this.nodeExtent,
|
||||
nodeOrigin: this.nodeOrigin,
|
||||
elevateNodesOnSelect: false,
|
||||
checkEquality: true
|
||||
});
|
||||
return true;
|
||||
});
|
||||
adoptEdges: true = $derived.by(() => {
|
||||
updateConnectionLookup(this.connectionLookup, this.edgeLookup, signals.edges);
|
||||
@@ -197,8 +196,8 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
edgesInitialized: boolean = $state(false);
|
||||
viewportInitialized: boolean = $state(false);
|
||||
|
||||
initialNodesLength: number = signals.nodes.length;
|
||||
initialEdgesLength: number = signals.edges.length;
|
||||
initialNodesLength: number = signals.nodes?.length ?? 0;
|
||||
initialEdgesLength: number = signals.edges?.length ?? 0;
|
||||
initialized: boolean = $derived.by(() => {
|
||||
let initialized = false;
|
||||
// if it hasn't been initialised check if it's now
|
||||
|
||||
@@ -93,6 +93,7 @@ export function adoptUserNodes<NodeType extends NodeBase>(
|
||||
nodeLookup.clear();
|
||||
parentLookup.clear();
|
||||
|
||||
const updatedChildNodes = new Set<string>();
|
||||
for (const userNode of nodes) {
|
||||
let internalNode = tmpLookup.get(userNode.id);
|
||||
|
||||
@@ -123,9 +124,10 @@ export function adoptUserNodes<NodeType extends NodeBase>(
|
||||
}
|
||||
|
||||
if (userNode.parentId) {
|
||||
updateChildNode(internalNode, nodeLookup, parentLookup, options);
|
||||
updateChildNode(internalNode, nodeLookup, parentLookup, options, updatedChildNodes);
|
||||
}
|
||||
}
|
||||
return updatedChildNodes;
|
||||
}
|
||||
|
||||
function updateParentLookup<NodeType extends NodeBase>(
|
||||
@@ -152,7 +154,8 @@ function updateChildNode<NodeType extends NodeBase>(
|
||||
node: InternalNodeBase<NodeType>,
|
||||
nodeLookup: NodeLookup<InternalNodeBase<NodeType>>,
|
||||
parentLookup: ParentLookup<InternalNodeBase<NodeType>>,
|
||||
options?: UpdateNodesOptions<NodeType>
|
||||
options?: UpdateNodesOptions<NodeType>,
|
||||
updatedChildNodes?: Set<string>
|
||||
) {
|
||||
const { elevateNodesOnSelect, nodeOrigin, nodeExtent } = mergeObjects(defaultOptions, options);
|
||||
const parentId = node.parentId!;
|
||||
@@ -178,6 +181,7 @@ function updateChildNode<NodeType extends NodeBase>(
|
||||
positionAbsolute: positionChanged ? { x, y } : positionAbsolute,
|
||||
z,
|
||||
};
|
||||
updatedChildNodes?.add(node.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user