From 1fb668d93651b1c2cd9152bf4b1d71ec69aa4179 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 18 Jan 2024 12:14:12 +0100 Subject: [PATCH 01/20] Added onInit and useInitialized hooks --- .../components/CallOnMount/CallOnMount.svelte | 14 +++++++++ .../src/lib/components/CallOnMount/index.ts | 1 + .../EdgeRenderer/EdgeRenderer.svelte | 14 ++++++++- .../container/SvelteFlow/SvelteFlow.svelte | 11 +++++++ .../src/lib/container/SvelteFlow/types.ts | 2 ++ .../svelte/src/lib/container/Zoom/Zoom.svelte | 8 ++++- .../svelte/src/lib/hooks/useInitialized.ts | 28 +++++++++++++++++ packages/svelte/src/lib/index.ts | 1 + packages/svelte/src/lib/store/index.ts | 31 +++++++++++++++++++ .../svelte/src/lib/store/initial-store.ts | 6 +++- 10 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 packages/svelte/src/lib/components/CallOnMount/CallOnMount.svelte create mode 100644 packages/svelte/src/lib/components/CallOnMount/index.ts create mode 100644 packages/svelte/src/lib/hooks/useInitialized.ts diff --git a/packages/svelte/src/lib/components/CallOnMount/CallOnMount.svelte b/packages/svelte/src/lib/components/CallOnMount/CallOnMount.svelte new file mode 100644 index 00000000..4184da6f --- /dev/null +++ b/packages/svelte/src/lib/components/CallOnMount/CallOnMount.svelte @@ -0,0 +1,14 @@ + diff --git a/packages/svelte/src/lib/components/CallOnMount/index.ts b/packages/svelte/src/lib/components/CallOnMount/index.ts new file mode 100644 index 00000000..3dee0d92 --- /dev/null +++ b/packages/svelte/src/lib/components/CallOnMount/index.ts @@ -0,0 +1 @@ +export { default as CallOnMount } from './CallOnMount.svelte'; diff --git a/packages/svelte/src/lib/container/EdgeRenderer/EdgeRenderer.svelte b/packages/svelte/src/lib/container/EdgeRenderer/EdgeRenderer.svelte index 663b72ea..420259c3 100644 --- a/packages/svelte/src/lib/container/EdgeRenderer/EdgeRenderer.svelte +++ b/packages/svelte/src/lib/container/EdgeRenderer/EdgeRenderer.svelte @@ -1,6 +1,7 @@
createMarkerIds(edges, { defaultColor, id }) ), + initialized: (() => { + console.log('This closure gets called'); + let initialized = false; + const initialNodesLength = get(store.nodes).length; + const initialEdgesLength = get(store.edges).length; + return derived( + [store.nodesInitialized, store.edgesInitialized, store.viewportInitialized], + ([nodesInitialized, edgesInitialized, viewportInitialized]) => { + console.log('Get the derived store even called?'); + // If it was already initialized once return true from then on + if (initialized) return initialized; + + // if it hasn't been initialised check if is now + if (initialNodesLength === 0) { + initialized = viewportInitialized; + return initialized; + } + if (initialEdgesLength === 0) { + initialized = viewportInitialized && nodesInitialized; + return initialized; + } + + initialized = viewportInitialized && nodesInitialized && edgesInitialized; + return initialized; + } + ); + })(), // actions syncNodeStores: (nodes) => syncNodeStores(store.nodes, nodes), diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index 26c57c86..85d5e84b 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -152,6 +152,10 @@ export const getInitialStore = ({ onconnect: writable(undefined), onconnectstart: writable(undefined), onconnectend: writable(undefined), - onbeforedelete: writable(undefined) + onbeforedelete: writable(undefined), + nodesInitialized: writable(false), + edgesInitialized: writable(false), + viewportInitialized: writable(false), + initialized: readable(false) }; }; From a4145a33bd8daa7b13f43746aa2dba06abca8e28 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Thu, 18 Jan 2024 12:28:01 +0100 Subject: [PATCH 02/20] Optimized useNodesInitialized selector --- packages/react/src/hooks/useNodesInitialized.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/react/src/hooks/useNodesInitialized.ts b/packages/react/src/hooks/useNodesInitialized.ts index e70ba7cd..3a278f6c 100644 --- a/packages/react/src/hooks/useNodesInitialized.ts +++ b/packages/react/src/hooks/useNodesInitialized.ts @@ -12,9 +12,15 @@ const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) => return false; } - return s.nodes - .filter((n) => (options.includeHiddenNodes ? true : !n.hidden)) - .every((n) => n[internalsSymbol]?.handleBounds !== undefined); + for (const node of s.nodes) { + if (options.includeHiddenNodes || !node.hidden) { + if (node[internalsSymbol]?.handleBounds === undefined) { + return false; + } + } + } + + return true; }; const defaultOptions = { From 601c7f1c15377d56de68be4d9a26e6eda64258f8 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 22 Jan 2024 11:26:02 +0100 Subject: [PATCH 03/20] Selection process is not interrupted by selectionKey being let go --- packages/react/src/container/FlowRenderer/index.tsx | 8 +++++--- packages/svelte/src/lib/container/Pane/Pane.svelte | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/react/src/container/FlowRenderer/index.tsx b/packages/react/src/container/FlowRenderer/index.tsx index 06d6fab6..2670be70 100644 --- a/packages/react/src/container/FlowRenderer/index.tsx +++ b/packages/react/src/container/FlowRenderer/index.tsx @@ -28,7 +28,9 @@ export type FlowRendererProps = Omit< children: ReactNode; }; -const selector = (s: ReactFlowState) => s.nodesSelectionActive; +const selector = (s: ReactFlowState) => { + return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive }; +}; const FlowRendererComponent = ({ children, @@ -67,13 +69,13 @@ const FlowRendererComponent = ({ onViewportChange, isControlledViewport, }: FlowRendererProps) => { - const nodesSelectionActive = useStore(selector); + const { nodesSelectionActive, userSelectionActive } = useStore(selector); const selectionKeyPressed = useKeyPress(selectionKeyCode); const panActivationKeyPressed = useKeyPress(panActivationKeyCode); const panOnDrag = panActivationKeyPressed || _panOnDrag; const panOnScroll = panActivationKeyPressed || _panOnScroll; - const isSelecting = selectionKeyPressed || (selectionOnDrag && panOnDrag !== true); + const isSelecting = selectionKeyPressed || userSelectionActive || (selectionOnDrag && panOnDrag !== true); useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }); diff --git a/packages/svelte/src/lib/container/Pane/Pane.svelte b/packages/svelte/src/lib/container/Pane/Pane.svelte index cce95636..f0df0980 100644 --- a/packages/svelte/src/lib/container/Pane/Pane.svelte +++ b/packages/svelte/src/lib/container/Pane/Pane.svelte @@ -73,7 +73,8 @@ let selectedNodes: Node[] = []; $: _panOnDrag = $panActivationKeyPressed || panOnDrag; - $: isSelecting = $selectionKeyPressed || (selectionOnDrag && _panOnDrag !== true); + $: isSelecting = + $selectionKeyPressed || $selectionRect || (selectionOnDrag && _panOnDrag !== true); $: hasActiveSelection = $elementsSelectable && (isSelecting || $selectionRectMode === 'user'); function onClick(event: MouseEvent | TouchEvent) { From efbf2b35824cdf68f82d1d4332602cb9785f5368 Mon Sep 17 00:00:00 2001 From: peterkogo Date: Mon, 22 Jan 2024 16:34:01 +0100 Subject: [PATCH 04/20] useInitialized and useNodesInitialized now return a readable, useEdgesInitialized is not exported --- packages/svelte/src/lib/hooks/useInitialized.ts | 9 +++++++-- packages/svelte/src/lib/index.ts | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/lib/hooks/useInitialized.ts b/packages/svelte/src/lib/hooks/useInitialized.ts index 93e6921b..09b0307c 100644 --- a/packages/svelte/src/lib/hooks/useInitialized.ts +++ b/packages/svelte/src/lib/hooks/useInitialized.ts @@ -1,4 +1,5 @@ import { useStore } from '$lib/store'; +import type { Readable } from 'svelte/store'; /** * Hook for seeing if nodes are initialized @@ -6,7 +7,9 @@ import { useStore } from '$lib/store'; */ export function useNodesInitialized() { const { nodesInitialized } = useStore(); - return nodesInitialized; + return { + subscribe: nodesInitialized.subscribe + } as Readable; } /** @@ -24,5 +27,7 @@ export function useEdgesInitialized() { */ export function useInitialized() { const { initialized } = useStore(); - return initialized; + return { + subscribe: initialized.subscribe + } as Readable; } diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index c88059b7..75f0092b 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -31,7 +31,7 @@ export * from '$lib/hooks/useConnection'; export * from '$lib/hooks/useNodesEdges'; export * from '$lib/hooks/useHandleConnections'; export * from '$lib/hooks/useNodesData'; -export * from '$lib/hooks/useInitialized'; +export { useInitialized, useNodesInitialized } from '$lib/hooks/useInitialized'; // types export type { From 33bf6b0e46162c6d0a76721650e5a241ac33b2bc Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 23 Jan 2024 10:08:10 +0100 Subject: [PATCH 05/20] chore(packages): update changelog --- packages/react/CHANGELOG.md | 1 + packages/svelte/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 70a3de11..57f65c83 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -4,6 +4,7 @@ ### Patch changes +- selection box is not interrupted by selectionKey being let go - fix `OnNodeDrag` type ## 12.0.0-next.7 diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 6b9e940a..0b9350a6 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -8,6 +8,7 @@ ## Patch changes +- selection box is not interrupted by selectionKey being let go - Edge label has a default background and is clickable ## 0.0.34 From 085f71d43527c839c69ae3c0953ddde5ffc94da3 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 23 Jan 2024 11:45:26 +0100 Subject: [PATCH 06/20] refactor(handles): do not use fallback handle if an id is being used #3409 --- packages/system/src/utils/edges/positions.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/system/src/utils/edges/positions.ts b/packages/system/src/utils/edges/positions.ts index 59b8cd42..8bb9f5df 100644 --- a/packages/system/src/utils/edges/positions.ts +++ b/packages/system/src/utils/edges/positions.ts @@ -114,11 +114,6 @@ function getHandle(bounds: HandleElement[], handleId?: string | null): HandleEle return null; } - if (bounds.length === 1 || !handleId) { - return bounds[0]; - } else if (handleId) { - return bounds.find((d) => d.id === handleId) || null; - } - - return null; + // if no handleId is given, we use the first handle, otherwise we check for the id + return (!handleId ? bounds[0] : bounds.find((d) => d.id === handleId)) || null; } From c6b669b21c750d1afb452de6c32e22e8c7ffec93 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 23 Jan 2024 11:46:18 +0100 Subject: [PATCH 07/20] chore(packages): update changelog --- packages/react/CHANGELOG.md | 1 + packages/svelte/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 70a3de11..9bfaa78e 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -5,6 +5,7 @@ ### Patch changes - fix `OnNodeDrag` type +- refactor(handles): do not use fallback handle if an id is being used #3409 ## 12.0.0-next.7 diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index 6b9e940a..23b550ea 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -9,6 +9,7 @@ ## Patch changes - Edge label has a default background and is clickable +- refactor(handles): do not use fallback handle if an id is being used #3409 ## 0.0.34 From 2e1bfc35c0ca13d1ea944867730c36dc89f0a925 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 23 Jan 2024 13:04:02 +0100 Subject: [PATCH 08/20] chore(onbeforedelete): use correct node/edge types, pass generic --- examples/react/src/examples/CustomNode/index.tsx | 4 ++++ packages/react/src/index.ts | 1 - packages/react/src/types/component-props.ts | 2 +- packages/react/src/types/general.ts | 6 ++++++ packages/react/src/types/store.ts | 2 +- packages/svelte/src/lib/store/initial-store.ts | 4 ++-- packages/svelte/src/lib/types/general.ts | 7 ++++++- packages/system/src/types/general.ts | 2 +- packages/system/src/utils/graph.ts | 4 ++-- 9 files changed, 23 insertions(+), 9 deletions(-) diff --git a/examples/react/src/examples/CustomNode/index.tsx b/examples/react/src/examples/CustomNode/index.tsx index 22433db0..a8c0f55d 100644 --- a/examples/react/src/examples/CustomNode/index.tsx +++ b/examples/react/src/examples/CustomNode/index.tsx @@ -15,6 +15,7 @@ import { applyNodeChanges, OnNodesChange, OnConnect, + OnBeforeDelete, } from '@xyflow/react'; import ColorSelectorNode from './ColorSelectorNode'; @@ -142,6 +143,8 @@ const CustomNodeFlow = () => { [setEdges] ); + const onBeforeDelete: OnBeforeDelete = useCallback(async (params) => true, []); + return ( { fitView minZoom={0.3} maxZoom={2} + onBeforeDelete={onBeforeDelete} > { diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 8ad67000..bcb12cdf 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -79,7 +79,6 @@ export { type ColorMode, type ColorModeClass, type HandleType, - type OnBeforeDelete, type ShouldResize, type OnResizeStart, type OnResize, diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index f8bc8dfd..6018e1f5 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -21,7 +21,6 @@ import type { IsValidConnection, ColorMode, SnapGrid, - OnBeforeDelete, } from '@xyflow/system'; import type { @@ -44,6 +43,7 @@ import type { SelectionDragHandler, EdgeMouseHandler, OnNodeDrag, + OnBeforeDelete, } from '.'; /** diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 1a7462ad..53d95d68 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -11,6 +11,7 @@ import { FitBounds, XYPosition, NodeProps, + OnBeforeDeleteBase, } from '@xyflow/system'; import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps } from '.'; @@ -59,3 +60,8 @@ export type ViewportHelperFunctions = { flowToScreenPosition: (position: XYPosition) => XYPosition; viewportInitialized: boolean; }; + +export type OnBeforeDelete = OnBeforeDeleteBase< + NodeType, + EdgeType +>; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index a0d5f8cc..b3e0449e 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -26,7 +26,6 @@ import { type EdgeLookup, type ConnectionLookup, type NodeLookup, - OnBeforeDelete, } from '@xyflow/system'; import type { @@ -43,6 +42,7 @@ import type { UnselectNodesAndEdgesParams, OnDelete, OnNodeDrag, + OnBeforeDelete, } from '.'; export type ReactFlowStore = { diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index 26c57c86..ea7b9118 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -23,7 +23,6 @@ import { type OnConnectStart, type OnConnectEnd, type NodeLookup, - type OnBeforeDelete, type EdgeLookup } from '@xyflow/system'; @@ -47,7 +46,8 @@ import type { Edge, FitViewOptions, OnDelete, - OnEdgeCreate + OnEdgeCreate, + OnBeforeDelete } from '$lib/types'; import { createNodesStore, createEdgesStore } from './utils'; import { initConnectionProps, type ConnectionProps } from './derived-connection-props'; diff --git a/packages/svelte/src/lib/types/general.ts b/packages/svelte/src/lib/types/general.ts index 4f5fa30b..e67ad88c 100644 --- a/packages/svelte/src/lib/types/general.ts +++ b/packages/svelte/src/lib/types/general.ts @@ -5,7 +5,8 @@ import type { Position, XYPosition, ConnectingHandle, - Connection + Connection, + OnBeforeDeleteBase } from '@xyflow/system'; import type { Node } from './nodes'; @@ -52,3 +53,7 @@ export type FitViewOptions = FitViewOptionsBase; export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void; export type OnEdgeCreate = (connection: Connection) => Edge | Connection | void; +export type OnBeforeDelete< + NodeType extends Node = Node, + EdgeType extends Edge = Edge +> = OnBeforeDeleteBase; diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index 5fe4a844..8ac3d6be 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -142,7 +142,7 @@ export type ColorMode = ColorModeClass | 'system'; export type ConnectionLookup = Map>; -export type OnBeforeDelete = ({ +export type OnBeforeDeleteBase = ({ nodes, edges, }: { diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index fa56a987..f7e177b9 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -22,7 +22,7 @@ import { NodeDragItem, CoordinateExtent, OnError, - OnBeforeDelete, + OnBeforeDeleteBase, } from '../types'; import { errorMessages } from '../constants'; @@ -347,7 +347,7 @@ export async function getElementsToRemove[]; nodes: NodeType[]; edges: EdgeType[]; - onBeforeDelete?: OnBeforeDelete; + onBeforeDelete?: OnBeforeDeleteBase; }): Promise<{ nodes: NodeType[]; edges: EdgeType[]; From 7348490e4c616c0ae1b20269f394599a7d99c4bf Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 23 Jan 2024 15:28:13 +0100 Subject: [PATCH 09/20] chore(svelte): cleanup init derived store --- .../src/routes/examples/overview/+page.svelte | 4 ++++ .../examples/overview/InitTracker.svelte | 18 ++++++++++++++++++ packages/svelte/src/lib/store/index.ts | 14 +++++--------- 3 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 examples/svelte/src/routes/examples/overview/InitTracker.svelte diff --git a/examples/svelte/src/routes/examples/overview/+page.svelte b/examples/svelte/src/routes/examples/overview/+page.svelte index 586af3b9..2f21107d 100644 --- a/examples/svelte/src/routes/examples/overview/+page.svelte +++ b/examples/svelte/src/routes/examples/overview/+page.svelte @@ -22,6 +22,7 @@ import CustomEdge from './CustomEdge.svelte'; import '@xyflow/svelte/dist/style.css'; + import InitTracker from './InitTracker.svelte'; const nodeTypes: NodeTypes = { custom: CustomNode, @@ -148,6 +149,7 @@ selectionMode={SelectionMode.Full} initialViewport={{ x: 100, y: 100, zoom: 2 }} snapGrid={[25, 25]} + oninit={() => console.log('on init')} on:nodeclick={(event) => console.log('on node click', event)} on:nodemouseenter={(event) => console.log('on node enter', event)} on:nodemouseleave={(event) => console.log('on node leave', event)} @@ -207,6 +209,8 @@ }}>hide/unhide + +