diff --git a/packages/react/src/hooks/useReactFlow.ts b/packages/react/src/hooks/useReactFlow.ts index 63b9df86..b67ef0d3 100644 --- a/packages/react/src/hooks/useReactFlow.ts +++ b/packages/react/src/hooks/useReactFlow.ts @@ -279,9 +279,11 @@ export function useReactFlow | undefined) => { - store.setState({ fitViewQueued: true, fitViewOptions: options }); + fitView: async (options: FitViewOptions | undefined) => { + const fitViewResolver = store.getState().fitViewResolver ?? Promise.withResolvers(); + store.setState({ fitViewQueued: true, fitViewOptions: options, fitViewResolver }); batchContext.nodeQueue.push((nodes) => [...nodes]); + return fitViewResolver.promise; }, }; }, []); diff --git a/packages/react/src/store/index.ts b/packages/react/src/store/index.ts index 64d1b405..909d8572 100644 --- a/packages/react/src/store/index.ts +++ b/packages/react/src/store/index.ts @@ -62,10 +62,9 @@ const createStore = ({ checkEquality: true, }); - let viewportFitted = false; if (fitViewQueued && nodesInitialized && panZoom) { - const { fitViewOptions, width, height, minZoom, maxZoom } = get(); - viewportFitted = fitViewport( + const { fitViewOptions, fitViewResolver, width, height, minZoom, maxZoom } = get(); + const fitViewPromise = fitViewport( { nodes: nodeLookup, width, @@ -76,9 +75,10 @@ const createStore = ({ }, fitViewOptions ); - } - - if (viewportFitted) { + fitViewPromise.then((value) => { + fitViewResolver?.resolve(value); + set({ fitViewResolver: null }); + }); set({ nodes, fitViewQueued: false, fitViewOptions: undefined }); } else { set({ nodes }); diff --git a/packages/react/src/store/initialState.ts b/packages/react/src/store/initialState.ts index 9005c99f..c63c9e9c 100644 --- a/packages/react/src/store/initialState.ts +++ b/packages/react/src/store/initialState.ts @@ -110,6 +110,7 @@ const getInitialState = ({ fitViewQueued: false, fitViewOptions: undefined, + fitViewResolver: null, connection: { ...initialConnection }, connectionClickStartHandle: null, diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 45dc93c1..11021b3a 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -109,7 +109,7 @@ export type FitViewParams = FitViewParamsBase = FitViewOptionsBase; -export type FitView = (fitViewOptions?: FitViewOptions) => void; +export type FitView = (fitViewOptions?: FitViewOptions) => Promise; export type OnInit = ( reactFlowInstance: ReactFlowInstance ) => void; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index 10814ecf..efd9d957 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -121,6 +121,7 @@ export type ReactFlowStore | null; onNodesDelete?: OnNodesDelete; onEdgesDelete?: OnEdgesDelete; diff --git a/packages/system/src/utils/graph.ts b/packages/system/src/utils/graph.ts index 84738faf..e14f81cd 100644 --- a/packages/system/src/utils/graph.ts +++ b/packages/system/src/utils/graph.ts @@ -351,16 +351,15 @@ function getFitViewNodes< return fitViewNodes; } -export function fitViewport, Options extends FitViewOptionsBase>( +export async function fitViewport< + Params extends FitViewParamsBase, + Options extends FitViewOptionsBase +>( { nodes, width, height, panZoom, minZoom, maxZoom }: Params, options?: Omit -): boolean { +): Promise { if (nodes.size === 0) { - return true; - } - - if (!panZoom) { - return false; + return Promise.resolve(true); } const nodesToFit = getFitViewNodes(nodes, options); @@ -376,9 +375,9 @@ export function fitViewport, Options options?.padding ?? 0.1 ); - panZoom.setViewport(viewport, { duration: options?.duration }); + await panZoom.setViewport(viewport, { duration: options?.duration }); - return true; + return Promise.resolve(true); } /**