Merge pull request #3811 from xyflow/svelte-on-init
Added onInit and useInitialized hooks
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
import CustomEdge from './CustomEdge.svelte';
|
import CustomEdge from './CustomEdge.svelte';
|
||||||
|
|
||||||
import '@xyflow/svelte/dist/style.css';
|
import '@xyflow/svelte/dist/style.css';
|
||||||
|
import InitTracker from './InitTracker.svelte';
|
||||||
|
|
||||||
const nodeTypes: NodeTypes = {
|
const nodeTypes: NodeTypes = {
|
||||||
custom: CustomNode,
|
custom: CustomNode,
|
||||||
@@ -148,6 +149,7 @@
|
|||||||
selectionMode={SelectionMode.Full}
|
selectionMode={SelectionMode.Full}
|
||||||
initialViewport={{ x: 100, y: 100, zoom: 2 }}
|
initialViewport={{ x: 100, y: 100, zoom: 2 }}
|
||||||
snapGrid={[25, 25]}
|
snapGrid={[25, 25]}
|
||||||
|
oninit={() => console.log('on init')}
|
||||||
on:nodeclick={(event) => console.log('on node click', event)}
|
on:nodeclick={(event) => console.log('on node click', event)}
|
||||||
on:nodemouseenter={(event) => console.log('on node enter', event)}
|
on:nodemouseenter={(event) => console.log('on node enter', event)}
|
||||||
on:nodemouseleave={(event) => console.log('on node leave', event)}
|
on:nodemouseleave={(event) => console.log('on node leave', event)}
|
||||||
@@ -207,6 +209,8 @@
|
|||||||
}}>hide/unhide</button
|
}}>hide/unhide</button
|
||||||
>
|
>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
|
<InitTracker />
|
||||||
</SvelteFlow>
|
</SvelteFlow>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { useNodesInitialized, useInitialized } from '@xyflow/svelte';
|
||||||
|
|
||||||
|
const nodesInitialized = useNodesInitialized();
|
||||||
|
const initialized = useInitialized();
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (nodesInitialized) {
|
||||||
|
console.log('nodes initialized');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
if (initialized) {
|
||||||
|
console.log('initialized');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -12,9 +12,15 @@ const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) =>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.nodes
|
for (const node of s.nodes) {
|
||||||
.filter((n) => (options.includeHiddenNodes ? true : !n.hidden))
|
if (options.includeHiddenNodes || !node.hidden) {
|
||||||
.every((n) => n[internalsSymbol]?.handleBounds !== undefined);
|
if (node[internalsSymbol]?.handleBounds === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
## Minor changes
|
## Minor changes
|
||||||
|
|
||||||
- add `getNode`, `getNodes`, `getEdge` and `getEdges` to `useSvelteFlow`
|
- add `getNode`, `getNodes`, `getEdge` and `getEdges` to `useSvelteFlow`
|
||||||
|
- add `useInitialized` / `useNNodesInitialized` hooks and `oninit` handler
|
||||||
|
|
||||||
## Patch changes
|
## Patch changes
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
let _onMount: (() => void) | undefined = undefined;
|
||||||
|
export { _onMount as onMount };
|
||||||
|
|
||||||
|
let _onDestroy: (() => void) | undefined = undefined;
|
||||||
|
export { _onDestroy as onDestroy };
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
_onMount?.();
|
||||||
|
return _onDestroy;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as CallOnMount } from './CallOnMount.svelte';
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { EdgeWrapper } from '$lib/components/EdgeWrapper';
|
import { EdgeWrapper } from '$lib/components/EdgeWrapper';
|
||||||
|
import { CallOnMount } from '$lib/components/CallOnMount';
|
||||||
import { MarkerDefinition } from '$lib/container/EdgeRenderer/MarkerDefinition';
|
import { MarkerDefinition } from '$lib/container/EdgeRenderer/MarkerDefinition';
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import type { DefaultEdgeOptions } from '$lib/types';
|
import type { DefaultEdgeOptions } from '$lib/types';
|
||||||
@@ -8,8 +9,8 @@
|
|||||||
export let defaultEdgeOptions: DefaultEdgeOptions | undefined;
|
export let defaultEdgeOptions: DefaultEdgeOptions | undefined;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
elementsSelectable,
|
|
||||||
visibleEdges,
|
visibleEdges,
|
||||||
|
edgesInitialized,
|
||||||
edges: { setDefaultOptions }
|
edges: { setDefaultOptions }
|
||||||
} = useStore();
|
} = useStore();
|
||||||
|
|
||||||
@@ -54,4 +55,15 @@
|
|||||||
on:edgecontextmenu
|
on:edgecontextmenu
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
{#if $visibleEdges.length > 0}
|
||||||
|
<CallOnMount
|
||||||
|
onMount={() => {
|
||||||
|
$edgesInitialized = true;
|
||||||
|
}}
|
||||||
|
onDestroy={() => {
|
||||||
|
$edgesInitialized = false;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
export let onconnectstart: $$Props['onconnectstart'] = undefined;
|
export let onconnectstart: $$Props['onconnectstart'] = undefined;
|
||||||
export let onconnectend: $$Props['onconnectend'] = undefined;
|
export let onconnectend: $$Props['onconnectend'] = undefined;
|
||||||
export let onbeforedelete: $$Props['onbeforedelete'] = undefined;
|
export let onbeforedelete: $$Props['onbeforedelete'] = undefined;
|
||||||
|
export let oninit: $$Props['oninit'] = undefined;
|
||||||
|
|
||||||
export let defaultMarkerColor = '#b1b1b7';
|
export let defaultMarkerColor = '#b1b1b7';
|
||||||
|
|
||||||
@@ -130,6 +131,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call oninit once when flow is intialized
|
||||||
|
const { initialized } = store;
|
||||||
|
let onInitCalled = false;
|
||||||
|
$: {
|
||||||
|
if (!onInitCalled && $initialized) {
|
||||||
|
oninit?.();
|
||||||
|
onInitCalled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this updates the store for simple changes
|
// this updates the store for simple changes
|
||||||
// where the prop names equals the store name
|
// where the prop names equals the store name
|
||||||
$: {
|
$: {
|
||||||
|
|||||||
@@ -333,4 +333,6 @@ export type SvelteFlowProps = DOMAttributes<HTMLDivElement> & {
|
|||||||
onconnectstart?: OnConnectStart;
|
onconnectstart?: OnConnectStart;
|
||||||
/** When a user stops dragging a connection line, this event gets fired. */
|
/** When a user stops dragging a connection line, this event gets fired. */
|
||||||
onconnectend?: OnConnectEnd;
|
onconnectend?: OnConnectEnd;
|
||||||
|
/** This handler gets called when the flow is finished initializing */
|
||||||
|
oninit?: () => void;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import zoom from '$lib/actions/zoom';
|
import zoom from '$lib/actions/zoom';
|
||||||
import type { ZoomProps } from './types';
|
import type { ZoomProps } from './types';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
type $$Props = ZoomProps;
|
type $$Props = ZoomProps;
|
||||||
|
|
||||||
@@ -29,12 +30,17 @@
|
|||||||
translateExtent,
|
translateExtent,
|
||||||
lib,
|
lib,
|
||||||
panActivationKeyPressed,
|
panActivationKeyPressed,
|
||||||
zoomActivationKeyPressed
|
zoomActivationKeyPressed,
|
||||||
|
viewportInitialized
|
||||||
} = useStore();
|
} = useStore();
|
||||||
|
|
||||||
$: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 };
|
$: viewPort = initialViewport || { x: 0, y: 0, zoom: 1 };
|
||||||
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
|
$: _panOnDrag = $panActivationKeyPressed || panOnDrag;
|
||||||
$: _panOnScroll = $panActivationKeyPressed || panOnScroll;
|
$: _panOnScroll = $panActivationKeyPressed || panOnScroll;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
$viewportInitialized = true;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { useStore } from '$lib/store';
|
||||||
|
import type { Readable } from 'svelte/store';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for seeing if nodes are initialized
|
||||||
|
* @returns - nodesInitialized Writable
|
||||||
|
*/
|
||||||
|
export function useNodesInitialized() {
|
||||||
|
const { nodesInitialized } = useStore();
|
||||||
|
return {
|
||||||
|
subscribe: nodesInitialized.subscribe
|
||||||
|
} as Readable<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for seeing if the flow is initialized
|
||||||
|
* @returns - initialized Writable
|
||||||
|
*/
|
||||||
|
export function useInitialized() {
|
||||||
|
const { initialized } = useStore();
|
||||||
|
return {
|
||||||
|
subscribe: initialized.subscribe
|
||||||
|
} as Readable<boolean>;
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@ export * from '$lib/hooks/useConnection';
|
|||||||
export * from '$lib/hooks/useNodesEdges';
|
export * from '$lib/hooks/useNodesEdges';
|
||||||
export * from '$lib/hooks/useHandleConnections';
|
export * from '$lib/hooks/useHandleConnections';
|
||||||
export * from '$lib/hooks/useNodesData';
|
export * from '$lib/hooks/useNodesData';
|
||||||
|
export { useInitialized, useNodesInitialized } from '$lib/hooks/useInitialized';
|
||||||
|
|
||||||
// types
|
// types
|
||||||
export type {
|
export type {
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ export function createStore({
|
|||||||
}
|
}
|
||||||
|
|
||||||
store.nodes.set(nextNodes);
|
store.nodes.set(nextNodes);
|
||||||
|
|
||||||
|
if (!get(store.nodesInitialized)) {
|
||||||
|
store.nodesInitialized.set(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fitView(nodes: Node[], options?: FitViewOptions) {
|
function fitView(nodes: Node[], options?: FitViewOptions) {
|
||||||
@@ -353,6 +357,29 @@ export function createStore({
|
|||||||
[store.edges, store.defaultMarkerColor, store.flowId],
|
[store.edges, store.defaultMarkerColor, store.flowId],
|
||||||
([edges, defaultColor, id]) => createMarkerIds(edges, { defaultColor, id })
|
([edges, defaultColor, id]) => createMarkerIds(edges, { defaultColor, id })
|
||||||
),
|
),
|
||||||
|
initialized: (() => {
|
||||||
|
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]) => {
|
||||||
|
// If it was already initialized, return true from then on
|
||||||
|
if (initialized) return initialized;
|
||||||
|
|
||||||
|
// if it hasn't been initialised check if it's now
|
||||||
|
if (initialNodesLength === 0) {
|
||||||
|
initialized = viewportInitialized;
|
||||||
|
} else if (initialEdgesLength === 0) {
|
||||||
|
initialized = viewportInitialized && nodesInitialized;
|
||||||
|
} else {
|
||||||
|
initialized = viewportInitialized && nodesInitialized && edgesInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})(),
|
||||||
|
|
||||||
// actions
|
// actions
|
||||||
syncNodeStores: (nodes) => syncNodeStores(store.nodes, nodes),
|
syncNodeStores: (nodes) => syncNodeStores(store.nodes, nodes),
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ export const getInitialStore = ({
|
|||||||
onconnect: writable<OnConnect>(undefined),
|
onconnect: writable<OnConnect>(undefined),
|
||||||
onconnectstart: writable<OnConnectStart>(undefined),
|
onconnectstart: writable<OnConnectStart>(undefined),
|
||||||
onconnectend: writable<OnConnectEnd>(undefined),
|
onconnectend: writable<OnConnectEnd>(undefined),
|
||||||
onbeforedelete: writable<OnBeforeDelete>(undefined)
|
onbeforedelete: writable<OnBeforeDelete>(undefined),
|
||||||
|
nodesInitialized: writable<boolean>(false),
|
||||||
|
edgesInitialized: writable<boolean>(false),
|
||||||
|
viewportInitialized: writable<boolean>(false),
|
||||||
|
initialized: readable<boolean>(false)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user