From c855dfe454fe69a66c3d9c64420b98455a81515a Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:04:22 +0100 Subject: [PATCH] feat(core): add viewport helper to state --- .../core/src/composables/useOnInitHandler.ts | 37 +++++++++++++++---- packages/core/src/composables/useViewport.ts | 6 +-- packages/core/src/store/actions.ts | 1 + packages/core/src/store/state.ts | 2 - packages/core/src/types/store.ts | 5 ++- tests/cypress/support/component.ts | 7 ++-- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/packages/core/src/composables/useOnInitHandler.ts b/packages/core/src/composables/useOnInitHandler.ts index 9d7eee8c..16998af0 100644 --- a/packages/core/src/composables/useOnInitHandler.ts +++ b/packages/core/src/composables/useOnInitHandler.ts @@ -4,12 +4,33 @@ import { useVueFlow } from './useVueFlow' export function useOnInitHandler() { const vfInstance = useVueFlow() - watch(vfInstance.viewportInitialized, (isInitialized) => { - if (isInitialized) { - setTimeout(() => { - vfInstance.emits.init(vfInstance) - vfInstance.emits.paneReady(vfInstance) - }, 1) - } - }) + watch( + () => vfInstance.viewportHelper.value.viewportInitialized, + (isInitialized) => { + if (isInitialized) { + setTimeout(() => { + // todo: call these when *nodes* are initialized instead of the viewport + // currently doesn't work quite right because the viewport dimensions are not yet available when the nodes are initialized + if (!vfInstance.fitViewOnInitDone.value && vfInstance.fitViewOnInit.value) { + vfInstance.fitView() + } + + vfInstance.fitViewOnInitDone.value = true + + // Here, we are making all nodes visible once we have the dimensions. + if (!document.querySelector('#vue-flow__initialized-styles')) { + const style = document.createElement('style') + style.id = 'vue-flow__initialized-styles' + document.head.appendChild(style) + + const css = `.vue-flow__node { visibility: visible !important; }` + style.appendChild(document.createTextNode(css)) + } + + vfInstance.emits.init(vfInstance) + vfInstance.emits.paneReady(vfInstance) + }, 1) + } + }, + ) } diff --git a/packages/core/src/composables/useViewport.ts b/packages/core/src/composables/useViewport.ts index 66e8ff39..b32bfb4f 100644 --- a/packages/core/src/composables/useViewport.ts +++ b/packages/core/src/composables/useViewport.ts @@ -3,7 +3,7 @@ import { computed } from 'vue' import type { ComputedGetters, D3Selection, GraphNode, Project, State, ViewportFunctions } from '../types' import { clampPosition, getRectOfNodes, getTransformForBounds, pointToRendererPoint, rendererPointToPoint, warn } from '../utils' -interface ExtendedViewport extends ViewportFunctions { +export interface ViewportHelper extends ViewportFunctions { viewportInitialized: boolean screenToFlowCoordinate: Project flowToScreenCoordinate: Project @@ -17,7 +17,7 @@ function noop() { return Promise.resolve(false) } -const initialViewportHelper: ExtendedViewport = { +const initialViewportHelper: ViewportHelper = { zoomIn: noop, zoomOut: noop, zoomTo: noop, @@ -72,7 +72,7 @@ export function useViewport(state: State, getters: ComputedGetters) { }) } - return computed(() => { + return computed(() => { const isInitialized = state.d3Zoom && state.d3Selection && state.dimensions.width && state.dimensions.height if (!isInitialized) { diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index e6b6de30..8fdb39ec 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -939,6 +939,7 @@ export function useActions( toObject, fromObject, updateNodeInternals, + viewportHelper, $reset, $destroy: () => {}, } diff --git a/packages/core/src/store/state.ts b/packages/core/src/store/state.ts index 89ecdbf7..b6b2ca92 100644 --- a/packages/core/src/store/state.ts +++ b/packages/core/src/store/state.ts @@ -51,8 +51,6 @@ function defaultState(): State { d3Selection: null, d3ZoomHandler: null, - viewportInitialized: false, - minZoom: 0.5, maxZoom: 2, diff --git a/packages/core/src/types/store.ts b/packages/core/src/types/store.ts index 74904543..b9e5ca86 100644 --- a/packages/core/src/types/store.ts +++ b/packages/core/src/types/store.ts @@ -1,5 +1,6 @@ import type { CSSProperties, ComputedRef, ToRefs } from 'vue' import type { KeyFilter } from '@vueuse/core' +import type { ViewportHelper } from '../composables' import type { Dimensions, ElementData, @@ -57,8 +58,6 @@ export interface State extends Omit { readonly d3Selection: D3Selection | null readonly d3ZoomHandler: D3ZoomHandler | null - viewportInitialized: boolean - /** use setMinZoom action to change minZoom */ minZoom: number /** use setMaxZoom action to change maxZoom */ @@ -291,6 +290,8 @@ export interface Actions extends ViewportFunctions { getConnectedEdges: (nodesOrId: Node[] | string) => GraphEdge[] /** pan the viewport; return indicates if a transform has happened or not */ panBy: (delta: XYPosition) => boolean + /** viewport helper instance */ + viewportHelper: ComputedRef /** reset state to defaults */ $reset: () => void diff --git a/tests/cypress/support/component.ts b/tests/cypress/support/component.ts index ba11718f..16693d6a 100644 --- a/tests/cypress/support/component.ts +++ b/tests/cypress/support/component.ts @@ -8,20 +8,19 @@ import { VueFlow } from '@vue-flow/core' import type { FlowProps } from '@vue-flow/core' function mountVueFlow(props?: FlowProps, attrs?: Record, slots?: Record) { - cy.mount(VueFlow as any, { + cy.mount(VueFlow, { props: { id: 'test', fitViewOnInit: true, ...props, } as FlowProps, attrs: { - key: 'flowy', style: { height: '100vh', width: '100vw', - }, + } as CSSStyleDeclaration, ...attrs, - } as Record, + }, slots, }) }