fixed subflows, cleaned up nodeRenderer, cleaned up nodewrapper

This commit is contained in:
peterkogo
2024-12-11 13:38:48 +01:00
parent dca2eb6f37
commit 1c67bf848f
10 changed files with 370 additions and 384 deletions
@@ -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}
+10 -14
View File
@@ -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.
+2
View File
@@ -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
+6 -2
View File
@@ -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);
}
}