migrate nodetoolbar

This commit is contained in:
peterkogo
2024-11-13 17:27:44 +01:00
parent 7ba4104602
commit fc642e8b3d
5 changed files with 51 additions and 48 deletions
@@ -38,5 +38,5 @@ export type NodeWrapperProps = Pick<
zIndex: number; zIndex: number;
node: InternalNode; node: InternalNode;
initialized: boolean; initialized: boolean;
nodeClickDistance: number; nodeClickDistance?: number;
}; };
@@ -2,13 +2,21 @@
import { onDestroy } from 'svelte'; import { onDestroy } from 'svelte';
import { nodeHasDimensions } from '@xyflow/system'; import { nodeHasDimensions } from '@xyflow/system';
import type { NodeEvents } from '$lib/types/events';
import { NodeWrapper } from '$lib/components/NodeWrapper'; import { NodeWrapper } from '$lib/components/NodeWrapper';
import { useStore } from '$lib/store'; import { useStore } from '$lib/store';
import type { NodeRendererProps } from './types';
type $$Props = NodeRendererProps; let {
nodeClickDistance,
export let nodeClickDistance: $$Props['nodeClickDistance'] = 0; onnodeclick,
onnodecontextmenu,
onnodemouseenter,
onnodemousemove,
onnodemouseleave,
onnodedrag,
onnodedragstart,
onnodedragstop
}: { nodeClickDistance?: number } & NodeEvents = $props();
const { const {
visibleNodes, visibleNodes,
@@ -82,14 +90,14 @@
parentId={node.parentId} parentId={node.parentId}
{resizeObserver} {resizeObserver}
{nodeClickDistance} {nodeClickDistance}
on:nodeclick {onnodeclick}
on:nodemouseenter {onnodemouseenter}
on:nodemousemove {onnodemousemove}
on:nodemouseleave {onnodemouseleave}
on:nodedrag {onnodedrag}
on:nodedragstart {onnodedragstart}
on:nodedragstop {onnodedragstop}
on:nodecontextmenu {onnodecontextmenu}
/> />
{/each} {/each}
</div> </div>
@@ -1,3 +0,0 @@
export type NodeRendererProps = {
nodeClickDistance?: number;
};
@@ -1,38 +1,32 @@
<script lang="ts"> <script lang="ts">
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import { Position, getNodeToolbarTransform } from '@xyflow/system'; import { Position, getNodeToolbarTransform } from '@xyflow/system';
import portal from '$lib/actions/portal';
import type { InternalNode } from '$lib/types';
import { useStore } from '$lib/store';
import type { NodeToolbarProps } from './types'; import portal from '$lib/actions/portal';
import { useStore } from '$lib/store';
import { useSvelteFlow } from '$lib/hooks/useSvelteFlow'; import { useSvelteFlow } from '$lib/hooks/useSvelteFlow';
type $$Props = NodeToolbarProps; import type { InternalNode } from '$lib/types';
import type { NodeToolbarProps } from './types';
export let nodeId: $$Props['nodeId'] = undefined; let {
export let position: $$Props['position'] = undefined; nodeId,
export let align: $$Props['align'] = undefined; position = Position.Top,
export let offset: $$Props['offset'] = undefined; align = 'center',
export let isVisible: $$Props['isVisible'] = undefined; offset = 10,
isVisible,
children
}: NodeToolbarProps = $props();
const { domNode, viewport, nodeLookup, nodes } = useStore(); const { domNode, viewport, nodeLookup, nodes } = useStore();
const { getNodesBounds } = useSvelteFlow(); const { getNodesBounds } = useSvelteFlow();
const contextNodeId = getContext<string>('svelteflow__node_id'); const contextNodeId = getContext<string>('svelteflow__node_id');
let transform: string; let toolbarNodes: InternalNode[] = $derived.by(() => {
let toolbarNodes: InternalNode[] = [];
let _offset = offset !== undefined ? offset : 10;
let _position = position !== undefined ? position : Position.Top;
let _align = align !== undefined ? align : 'center';
$: {
// nly needed to trigger updates, $nodeLookup is just a helper that does not trigger any updates
$nodes; $nodes;
const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId ?? contextNodeId];
const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId || contextNodeId]; return nodeIds.reduce<InternalNode[]>((res, nodeId) => {
toolbarNodes = nodeIds.reduce<InternalNode[]>((res, nodeId) => {
const node = $nodeLookup.get(nodeId); const node = $nodeLookup.get(nodeId);
if (node) { if (node) {
@@ -41,29 +35,31 @@
return res; return res;
}, []); }, []);
} });
$: { let transform: string = $derived.by(() => {
const nodeRect = getNodesBounds(toolbarNodes); const nodeRect = getNodesBounds(toolbarNodes);
if (nodeRect) { if (nodeRect) {
transform = getNodeToolbarTransform(nodeRect, $viewport, _position, _offset, _align); return getNodeToolbarTransform(nodeRect, $viewport, position, offset, align);
} }
} return '';
});
$: zIndex = let zIndex = $derived(
toolbarNodes.length === 0 toolbarNodes.length === 0
? 1 ? 1
: Math.max(...toolbarNodes.map((node) => (node.internals.z || 5) + 1)); : Math.max(...toolbarNodes.map((node) => (node.internals.z || 5) + 1))
);
//FIXME: Possible performance bottleneck //FIXME: Possible performance bottleneck
$: selectedNodesCount = $nodes.filter((node) => node.selected).length; let selectedNodesCount = $derived($nodes.filter((node) => node.selected).length);
// if isVisible is not set, we show the toolbar only if its node is selected and no other node is selected // if isVisible is not set, we show the toolbar only if its node is selected and no other node is selected
$: isActive = let isActive = $derived(
typeof isVisible === 'boolean' typeof isVisible === 'boolean'
? isVisible ? isVisible
: toolbarNodes.length === 1 && toolbarNodes[0].selected && selectedNodesCount === 1; : toolbarNodes.length === 1 && toolbarNodes[0].selected && selectedNodesCount === 1
);
</script> </script>
{#if $domNode && isActive && toolbarNodes} {#if $domNode && isActive && toolbarNodes}
@@ -75,6 +71,6 @@
style:transform style:transform
style:z-index={zIndex} style:z-index={zIndex}
> >
<slot /> {@render children?.()}
</div> </div>
{/if} {/if}
@@ -1,4 +1,5 @@
import type { Position, Align } from '@xyflow/system'; import type { Position, Align } from '@xyflow/system';
import type { Snippet } from 'svelte';
export type NodeToolbarProps = { export type NodeToolbarProps = {
/** The id of the node, or array of ids the toolbar should be displayed at */ /** The id of the node, or array of ids the toolbar should be displayed at */
@@ -16,4 +17,5 @@ export type NodeToolbarProps = {
offset?: number; offset?: number;
/** If true, node toolbar is visible even if node is not selected */ /** If true, node toolbar is visible even if node is not selected */
isVisible?: boolean; isVisible?: boolean;
children?: Snippet;
}; };