From f3732a3988e5f5463bbc85d68b703e02b7cac30f Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 17 Feb 2023 16:58:06 +0100 Subject: [PATCH 01/78] refactor(core)!: update handle styles Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/style.css | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/core/src/style.css b/packages/core/src/style.css index 2c6011d45..e9fa6b363 100644 --- a/packages/core/src/style.css +++ b/packages/core/src/style.css @@ -187,28 +187,27 @@ } &-bottom { - top: auto; left: 50%; - bottom: -4px; - transform: translate(-50%, 0); + bottom: 0; + transform: translate(-50%, 50%); } &-top { left: 50%; - top: -4px; - transform: translate(-50%, 0); + top: 0; + transform: translate(-50%, -50%); } &-left { top: 50%; - left: -4px; - transform: translate(0, -50%); + left: 0; + transform: translate(-50%, -50%); } &-right { - right: -4px; top: 50%; - transform: translate(0, -50%); + right: 0; + transform: translate(50%, -50%); } } From fccea178688550ee95044266079604227fd0ef6f Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 17 Feb 2023 17:00:09 +0100 Subject: [PATCH 02/78] chore: add changeset Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/hip-melons-peel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/hip-melons-peel.md diff --git a/.changeset/hip-melons-peel.md b/.changeset/hip-melons-peel.md new file mode 100644 index 000000000..80e55c5b8 --- /dev/null +++ b/.changeset/hip-melons-peel.md @@ -0,0 +1,5 @@ +--- +'@vue-flow/core': major +--- + +Update handle styles and avoid using fixed pixel positions to offset handle position and instead use transform to align handles From 95437ba7a5bb78f4ad229b19ab129c61de77b1be Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 24 Feb 2023 20:28:08 +0100 Subject: [PATCH 03/78] chore: fix package versions together Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/config.json b/.changeset/config.json index 2df85f405..312fde6c2 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -6,7 +6,7 @@ "repo": "bcakmakoglu/vue-flow" } ], - "fixed": [], + "fixed": [["@vue-flow/*"]], "updateInternalDependencies": "patch", "snapshot": { "useCalculatedVersion": true From d43421b76fa93b226c0052bb873b31a9e2642375 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Thu, 16 Feb 2023 19:45:19 +0100 Subject: [PATCH 04/78] refactor(core)!: remove experimental features flag Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/store/actions.ts | 33 ++++-------------------------- packages/core/src/store/state.ts | 7 +------ packages/core/src/types/flow.ts | 4 ---- 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index 1540afabf..11306b19e 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -130,36 +130,11 @@ export function useActions( return } - // todo: remove this feature again, it's not working properly - let zoom: number - if (state.__experimentalFeatures?.nestedFlow) { - let viewportNodes: HTMLElement[] = [viewportNode] - let parentNode = viewportNode - let isNested - - while (!isNested && parentNode) { - parentNode = parentNode.parentElement! - isNested = parentNode?.classList.contains('vue-flow__transformationpane') - - if (isNested) { - viewportNodes = [parentNode, ...viewportNodes] - } - } + const style = window.getComputedStyle(viewportNode) - viewportNodes.forEach((vp) => { - const style = window.getComputedStyle(vp) - const { m22 } = new window.DOMMatrixReadOnly(style.transform) - if (!zoom) { - zoom = m22 - } else { - zoom *= m22 - } - }) - } else { - const style = window.getComputedStyle(viewportNode) - const { m22 } = new window.DOMMatrixReadOnly(style.transform) - zoom = m22 - } + const { m22 } = new window.DOMMatrixReadOnly(style.transform) + + const zoom = m22 const changes: NodeDimensionChange[] = updates.reduce((res, update) => { const node = findNode(update.id) diff --git a/packages/core/src/store/state.ts b/packages/core/src/store/state.ts index 7a34cc044..f7564d046 100644 --- a/packages/core/src/store/state.ts +++ b/packages/core/src/store/state.ts @@ -130,12 +130,7 @@ function defaultState(): State { disableKeyboardA11y: false, ariaLiveMessage: '', - - __experimentalFeatures: { - nestedFlow: false, - }, - } -} +}} export function useState(opts?: FlowOptions): State { const state = defaultState() diff --git a/packages/core/src/types/flow.ts b/packages/core/src/types/flow.ts index ab9d46ce6..5c627ebd1 100644 --- a/packages/core/src/types/flow.ts +++ b/packages/core/src/types/flow.ts @@ -180,10 +180,6 @@ export interface FlowProps { autoPanOnConnect?: boolean autoPanOnNodeDrag?: boolean - - __experimentalFeatures?: { - nestedFlow?: boolean - } } // Todo: Remove in next major version From c89190cc1cc690db1b0a97e8c195464b21c3226f Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 24 Feb 2023 20:26:17 +0100 Subject: [PATCH 05/78] chore: add changeset Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/cyan-melons-unite.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cyan-melons-unite.md diff --git a/.changeset/cyan-melons-unite.md b/.changeset/cyan-melons-unite.md new file mode 100644 index 000000000..b967de82a --- /dev/null +++ b/.changeset/cyan-melons-unite.md @@ -0,0 +1,5 @@ +--- +"@vue-flow/core": major +--- + +Remove experimental features flag From 0d0d90956129b327b64f1d53fed896f10862dbbb Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:16:05 +0100 Subject: [PATCH 06/78] refactor(core): `GraphNode`, `GraphEdge` as generic for `findNode`, `findEdge` actions Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/types/store.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/core/src/types/store.ts b/packages/core/src/types/store.ts index 81f251843..a4d476862 100644 --- a/packages/core/src/types/store.ts +++ b/packages/core/src/types/store.ts @@ -2,7 +2,6 @@ import type { CSSProperties, ComputedRef, ToRefs } from 'vue' import type { KeyFilter } from '@vueuse/core' import type { Dimensions, - ElementData, Elements, FlowElements, FlowExportObject, @@ -25,7 +24,7 @@ import type { import type { DefaultEdgeOptions, Edge, EdgeUpdatable, GraphEdge } from './edge' import type { CoordinateExtent, CoordinateExtentRange, GraphNode, Node } from './node' import type { D3Selection, D3Zoom, D3ZoomHandler, PanOnScrollMode, ViewportFunctions, ViewportTransform } from './zoom' -import type { CustomEvent, FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks' +import type { FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks' import type { EdgeChange, NodeChange, NodeDragItem } from './changes' import type { ConnectingHandle, ValidConnectionFunc } from './handle' @@ -182,13 +181,9 @@ export type UpdateNodeDimensions = (updates: UpdateNodeDimensionsParams[]) => vo export type UpdateNodeInternals = (nodeIds?: string[]) => void -export type FindNode = = any>( - id: string | undefined | null, -) => GraphNode | undefined +export type FindNode = (id: string | undefined | null) => T | undefined -export type FindEdge = = any>( - id: string | undefined | null, -) => GraphEdge | undefined +export type FindEdge = (id: string | undefined | null) => T | undefined export type GetIntersectingNodes = ( node: (Partial & { id: Node['id'] }) | Rect, From 8e4ef50c21a7c21ce9e0bf786b0d9457faeea616 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:16:48 +0100 Subject: [PATCH 07/78] chore: add changeset Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/fluffy-pans-boil.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fluffy-pans-boil.md diff --git a/.changeset/fluffy-pans-boil.md b/.changeset/fluffy-pans-boil.md new file mode 100644 index 000000000..2c49924b8 --- /dev/null +++ b/.changeset/fluffy-pans-boil.md @@ -0,0 +1,5 @@ +--- +'@vue-flow/core': minor +--- + +Use `GraphNode` or `GraphEdge` as optional generic types for `findNode` or `findEdge` actions From 93bed0d95dc7f8dd64f2896ed22caaa7f08cf8c2 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 1 Feb 2023 23:35:00 +0100 Subject: [PATCH 08/78] refactor(core): change generic of `useNode`, `useEdges` Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/composables/useEdge.ts | 6 +++--- packages/core/src/composables/useNode.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/core/src/composables/useEdge.ts b/packages/core/src/composables/useEdge.ts index d699ec7c6..17662035a 100644 --- a/packages/core/src/composables/useEdge.ts +++ b/packages/core/src/composables/useEdge.ts @@ -1,6 +1,6 @@ import { inject } from 'vue' import { useVueFlow } from './useVueFlow' -import type { CustomEvent, ElementData } from '~/types' +import type { GraphEdge } from '~/types' import { ErrorCode, VueFlowError } from '~/utils' import { EdgeId, EdgeRef } from '~/context' @@ -11,13 +11,13 @@ import { EdgeId, EdgeRef } from '~/context' * * Meaning if you do not provide an id, this composable has to be called in a child of your custom edge component, or it will throw */ -export function useEdge = any>(id?: string) { +export function useEdge(id?: string) { const edgeId = id ?? inject(EdgeId, '') const edgeEl = inject(EdgeRef, null) const { findEdge, emits } = useVueFlow() - const edge = findEdge(edgeId) + const edge = findEdge(edgeId) if (!edge) { emits.error(new VueFlowError(ErrorCode.EDGE_NOT_FOUND, edgeId)) diff --git a/packages/core/src/composables/useNode.ts b/packages/core/src/composables/useNode.ts index ede884949..2e1c71e85 100644 --- a/packages/core/src/composables/useNode.ts +++ b/packages/core/src/composables/useNode.ts @@ -1,6 +1,6 @@ import { computed, inject } from 'vue' import { useVueFlow } from './useVueFlow' -import type { CustomEvent, ElementData } from '~/types' +import type { GraphNode } from '~/types' import { NodeId, NodeRef } from '~/context' import { ErrorCode, VueFlowError, getConnectedEdges } from '~/utils' @@ -11,13 +11,13 @@ import { ErrorCode, VueFlowError, getConnectedEdges } from '~/utils' * * Meaning if you do not provide an id, this composable has to be called in a child of your custom node component, or it will throw */ -export function useNode = any>(id?: string) { +export function useNode(id?: string) { const nodeId = id ?? inject(NodeId, '') const nodeEl = inject(NodeRef, null) const { findNode, edges, emits } = useVueFlow() - const node = findNode(nodeId)! + const node = findNode(nodeId)! if (!node) { emits.error(new VueFlowError(ErrorCode.NODE_NOT_FOUND, nodeId)) From ce9a51db88eacc20b2424f6b2101bf1ae7781a6e Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 17 Mar 2023 19:57:09 +0100 Subject: [PATCH 09/78] chore(core): update find action types Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/store/actions.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index 11306b19e..79568c8c4 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -63,28 +63,34 @@ export function useActions( state.hooks.updateNodeInternals.trigger(updateIds) } - const findNode: Actions['findNode'] = (id) => { + const findNode: Actions['findNode'] = (id) => { if (!id) { return } + let node if (state.nodes && !nodeIds.value.length) { - return state.nodes.find((node) => node.id === id) + node = state.nodes.find((node) => node.id === id) + } else { + node = state.nodes[nodeIds.value.indexOf(id)] } - return state.nodes[nodeIds.value.indexOf(id)] + return node as T | undefined } - const findEdge: Actions['findEdge'] = (id) => { + const findEdge: Actions['findEdge'] = (id) => { if (!id) { return } + let edge if (state.edges && !edgeIds.value.length) { - return state.edges.find((edge) => edge.id === id) + edge = state.edges.find((edge) => edge.id === id) + } else { + edge = state.edges[edgeIds.value.indexOf(id)] } - return state.edges[edgeIds.value.indexOf(id)] + return edge as T | undefined } const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => { From ae8218035d557b864c300ae42a574815fd171070 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sat, 18 Mar 2023 11:33:14 +0100 Subject: [PATCH 10/78] chore: update changeset Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/fluffy-pans-boil.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/fluffy-pans-boil.md b/.changeset/fluffy-pans-boil.md index 2c49924b8..7357194ab 100644 --- a/.changeset/fluffy-pans-boil.md +++ b/.changeset/fluffy-pans-boil.md @@ -1,5 +1,5 @@ --- -'@vue-flow/core': minor +'@vue-flow/core': major --- Use `GraphNode` or `GraphEdge` as optional generic types for `findNode` or `findEdge` actions From 3cd01e5060c523e2224cf3eb89f53751adc6c974 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:39:27 +0100 Subject: [PATCH 11/78] chore(changeset): enter pre mode Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .changeset/pre.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .changeset/pre.json diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..fac142e7f --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,27 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "@vue-flow/docs": "1.0.0", + "@vue-flow/examples-nuxt3": "0.0.0", + "@vue-flow/examples-quasar": "0.0.0", + "@vue-flow/examples-vite": "0.0.0", + "@vue-flow/background": "1.0.5", + "@vue-flow/controls": "1.0.4", + "@vue-flow/core": "1.16.5", + "@vue-flow/minimap": "1.0.4", + "@vue-flow/node-resizer": "1.3.0", + "@vue-flow/node-toolbar": "1.0.6", + "@vue-flow/pathfinding-edge": "1.0.5", + "vueflow": "1.0.0", + "@vue-flow/tests": "0.0.0", + "@tooling/eslint-config": "0.0.0", + "@tooling/tsconfig": "0.0.0", + "@tooling/vite-config": "0.0.0" + }, + "changesets": [ + "cyan-melons-unite.md", + "fluffy-pans-boil.md", + "hip-melons-peel.md" + ] +} From e5bb526206af0d7aac14f442ecd7d01ddb1a58eb Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sun, 2 Apr 2023 21:45:49 +0200 Subject: [PATCH 12/78] chore(core): cleanup Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/store/actions.ts | 4 ++-- packages/core/src/store/state.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core/src/store/actions.ts b/packages/core/src/store/actions.ts index 79568c8c4..4a56059d5 100644 --- a/packages/core/src/store/actions.ts +++ b/packages/core/src/store/actions.ts @@ -63,7 +63,7 @@ export function useActions( state.hooks.updateNodeInternals.trigger(updateIds) } - const findNode: Actions['findNode'] = (id) => { + const findNode: Actions['findNode'] = (id: string | undefined | null) => { if (!id) { return } @@ -78,7 +78,7 @@ export function useActions( return node as T | undefined } - const findEdge: Actions['findEdge'] = (id) => { + const findEdge: Actions['findEdge'] = (id: string | undefined | null) => { if (!id) { return } diff --git a/packages/core/src/store/state.ts b/packages/core/src/store/state.ts index f7564d046..b8e89568e 100644 --- a/packages/core/src/store/state.ts +++ b/packages/core/src/store/state.ts @@ -130,7 +130,8 @@ function defaultState(): State { disableKeyboardA11y: false, ariaLiveMessage: '', -}} + } +} export function useState(opts?: FlowOptions): State { const state = defaultState() From 2ccf13329c6a21f410441e8692ba7cd45ca627ab Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:43:31 +0200 Subject: [PATCH 13/78] feat(core): add plugin API --- packages/core/src/composables/useVueFlow.ts | 84 +--------------- packages/core/src/index.ts | 4 +- packages/core/src/storage/index.ts | 1 + packages/core/src/storage/storage.ts | 102 ++++++++++++++++++++ packages/core/src/types/index.ts | 1 + packages/core/src/types/plugins.ts | 12 +++ packages/vue-flow/src/index.ts | 5 + 7 files changed, 127 insertions(+), 82 deletions(-) create mode 100644 packages/core/src/storage/index.ts create mode 100644 packages/core/src/storage/storage.ts create mode 100644 packages/core/src/types/plugins.ts diff --git a/packages/core/src/composables/useVueFlow.ts b/packages/core/src/composables/useVueFlow.ts index 74145fc7b..4936aa245 100644 --- a/packages/core/src/composables/useVueFlow.ts +++ b/packages/core/src/composables/useVueFlow.ts @@ -1,87 +1,11 @@ -import { toRefs, tryOnScopeDispose } from '@vueuse/core' +import { tryOnScopeDispose } from '@vueuse/core' import type { EffectScope } from 'vue' -import { computed, getCurrentScope, inject, provide, reactive } from 'vue' -import { useActions, useGetters, useState } from '~/store' -import type { FlowOptions, FlowProps, State, VueFlowStore } from '~/types' +import { Storage } from '~/storage' +import { getCurrentScope, inject, provide, reactive } from 'vue' +import type { FlowProps, VueFlowStore } from '~/types' import { VueFlow } from '~/context' import { warn } from '~/utils' -/** - * Stores all currently created store instances - */ -export class Storage { - public currentId = 0 - public flows = new Map() - static instance: Storage - - public static getInstance(): Storage { - if (!Storage.instance) { - Storage.instance = new Storage() - } - - return Storage.instance - } - - public set(id: string, flow: VueFlowStore) { - return this.flows.set(id, flow) - } - - public get(id: string) { - return this.flows.get(id) - } - - public remove(id: string) { - return this.flows.delete(id) - } - - public create(id: string, preloadedState?: FlowOptions): VueFlowStore { - const state: State = useState(preloadedState) - - const reactiveState = reactive(state) - - const nodeIds = computed(() => reactiveState.nodes.map((n) => n.id)) - const edgeIds = computed(() => reactiveState.edges.map((e) => e.id)) - - const getters = useGetters(reactiveState, nodeIds, edgeIds) - - const actions = useActions(reactiveState, getters, nodeIds, edgeIds) - - const hooksOn = {} - Object.entries(reactiveState.hooks).forEach(([n, h]) => { - const name = `on${n.charAt(0).toUpperCase() + n.slice(1)}` - hooksOn[name] = h.on - }) - - const emits = {} - Object.entries(reactiveState.hooks).forEach(([n, h]) => { - emits[n] = h.trigger - }) - - actions.setState(reactiveState) - - const flow: VueFlowStore = { - ...hooksOn, - ...getters, - ...actions, - ...toRefs(reactiveState), - emits, - id, - vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : 'UNKNOWN', - $destroy: () => { - this.remove(id) - }, - } - - this.set(id, flow) - - return flow - } - - public getId() { - return `vue-flow-${this.currentId++}` - } -} - type Injection = VueFlowStore | null | undefined type Scope = (EffectScope & { vueFlowId: string }) | undefined diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d05a199ef..cf8a1e72a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,6 @@ /** - * Vue Flow - * @module vue-flow + * Vue Flow Core pkg + * @module @vue-flow/core */ export { default as VueFlow } from './container/VueFlow/VueFlow.vue' diff --git a/packages/core/src/storage/index.ts b/packages/core/src/storage/index.ts new file mode 100644 index 000000000..69b61ecc4 --- /dev/null +++ b/packages/core/src/storage/index.ts @@ -0,0 +1 @@ +export * from './storage' diff --git a/packages/core/src/storage/storage.ts b/packages/core/src/storage/storage.ts new file mode 100644 index 000000000..c539c178d --- /dev/null +++ b/packages/core/src/storage/storage.ts @@ -0,0 +1,102 @@ +import type { FlowOptions, Plugin, State, VueFlowStore } from '~/types' +import { useActions, useGetters, useState } from '~/store' + +/** + * Stores all currently created store instances + */ +export class Storage { + public currentId = 0 + public flows = new Map() + static instance: Storage + private hooks = { + beforeCreate: createEventHook<[string, FlowOptions | undefined]>(), + created: createEventHook(), + beforeDestroy: createEventHook(), + destroyed: createEventHook(), + } + + public static getInstance(): Storage { + if (!Storage.instance) { + Storage.instance = new Storage() + } + + return Storage.instance + } + + public set(id: string, flow: VueFlowStore) { + return this.flows.set(id, flow) + } + + public get(id: string) { + return this.flows.get(id) + } + + public remove(id: string) { + return this.flows.delete(id) + } + + public create(id: string, preloadedState?: FlowOptions): VueFlowStore { + this.hooks.beforeCreate.trigger([id, preloadedState]) + const state: State = useState(preloadedState) + + const reactiveState = reactive(state) + + const getters = useGetters(reactiveState) + + const actions = useActions(reactiveState, getters) + + const hooksOn = {} + Object.entries(reactiveState.hooks).forEach(([n, h]) => { + const name = `on${n.charAt(0).toUpperCase() + n.slice(1)}` + hooksOn[name] = h.on + }) + + const emits = {} + Object.entries(reactiveState.hooks).forEach(([n, h]) => { + emits[n] = h.trigger + }) + + actions.setState(reactiveState) + + if (preloadedState) { + if (preloadedState.modelValue) actions.setElements(preloadedState.modelValue) + if (preloadedState.nodes) actions.setNodes(preloadedState.nodes) + if (preloadedState.edges) actions.setEdges(preloadedState.edges) + } + + const flow: VueFlowStore = { + ...hooksOn, + ...getters, + ...actions, + ...toRefs(reactiveState), + emits, + id, + $destroy: () => { + this.hooks.beforeDestroy.trigger(flow) + this.remove(id) + this.hooks.destroyed.trigger(id) + }, + } + + this.set(id, flow) + + this.hooks.created.trigger(flow) + + return flow + } + + public getId() { + return `vue-flow-${this.currentId++}` + } + + public install(plugins: Plugin[]) { + plugins.forEach((plugin) => + plugin({ + onBeforeCreate: this.hooks.beforeCreate.on, + created: this.hooks.created.on, + beforeDestroy: this.hooks.beforeDestroy.on, + destroyed: this.hooks.destroyed.on, + }), + ) + } +} diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index e87239809..e45b64759 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -9,3 +9,4 @@ export * from './hooks' export * from './changes' export * from './handle' export * from './panel' +export * from './plugins' diff --git a/packages/core/src/types/plugins.ts b/packages/core/src/types/plugins.ts new file mode 100644 index 000000000..2366a24b5 --- /dev/null +++ b/packages/core/src/types/plugins.ts @@ -0,0 +1,12 @@ +import type { EventHookOn } from '@vueuse/core' +import type { FlowOptions } from './flow' +import type { VueFlowStore } from './store' + +export interface PluginHooks { + onBeforeCreate: EventHookOn<[string, FlowOptions | undefined]> + created: EventHookOn + beforeDestroy: EventHookOn + destroyed: EventHookOn +} + +export type Plugin = (hooks: PluginHooks) => void diff --git a/packages/vue-flow/src/index.ts b/packages/vue-flow/src/index.ts index 5b0d106b1..06af3674d 100644 --- a/packages/vue-flow/src/index.ts +++ b/packages/vue-flow/src/index.ts @@ -1,3 +1,8 @@ +/** + * Vue Flow + * @module vue-flow + */ + import '@vue-flow/core/dist/style.css' import '@vue-flow/core/dist/theme-default.css' import '@vue-flow/controls/dist/style.css' From 61a81b38011f698dfd4cc90fa7a6ed3ec5c3631a Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:44:00 +0200 Subject: [PATCH 14/78] feat(core): add `StoreBase` interface for interface declaration merges --- packages/core/src/types/store.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/core/src/types/store.ts b/packages/core/src/types/store.ts index a4d476862..43701f4d8 100644 --- a/packages/core/src/types/store.ts +++ b/packages/core/src/types/store.ts @@ -308,12 +308,11 @@ export type ComputedGetters = { [key in keyof Getters]: ComputedRef } -export type VueFlowStore = { +export interface StoreBase { readonly id: string readonly emits: FlowHooksEmit /** current vue flow version you're using */ readonly vueFlowVersion: string -} & FlowHooksOn & - ToRefs & - Readonly & - Readonly +} + +export type VueFlowStore = StoreBase & FlowHooksOn & ToRefs & Readonly & Readonly From e7e77e7052b77934acac320ccf47f4caf977fa81 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:45:31 +0200 Subject: [PATCH 15/78] chore: add changeset --- .changeset/weak-points-whisper.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .changeset/weak-points-whisper.md diff --git a/.changeset/weak-points-whisper.md b/.changeset/weak-points-whisper.md new file mode 100644 index 000000000..d527e6c2d --- /dev/null +++ b/.changeset/weak-points-whisper.md @@ -0,0 +1,16 @@ +--- +'@vue-flow/core': minor +'vueflow': minor +--- + +Add plugin API to Vue Flow Storage + +## Summary + +- Add plugin API to Vue Flow Storage +- Allows to add plugins that can add custom functionality to the store +- Provides hooks for + - `beforeCreate` - before a store is created + - `created` - after a store has been created + - `beforeDestroy` - before a store is destroyed + - `destroyed` - after a store has been destroyed From 8241f80f1f24b28410d5fcb769dfc8c927bdc189 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:50:09 +0200 Subject: [PATCH 16/78] chore(core): move `Storage` class to utils dir --- packages/core/src/composables/useVueFlow.ts | 4 ++-- packages/core/src/index.ts | 2 ++ packages/core/src/storage/index.ts | 1 - packages/core/src/{storage => utils}/storage.ts | 0 4 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 packages/core/src/storage/index.ts rename packages/core/src/{storage => utils}/storage.ts (100%) diff --git a/packages/core/src/composables/useVueFlow.ts b/packages/core/src/composables/useVueFlow.ts index 4936aa245..a6fd09824 100644 --- a/packages/core/src/composables/useVueFlow.ts +++ b/packages/core/src/composables/useVueFlow.ts @@ -1,10 +1,10 @@ import { tryOnScopeDispose } from '@vueuse/core' import type { EffectScope } from 'vue' -import { Storage } from '~/storage' +import type { FlowProps, VueFlowStore } from '~/types' +import { warn, Storage } from '~/storage' import { getCurrentScope, inject, provide, reactive } from 'vue' import type { FlowProps, VueFlowStore } from '~/types' import { VueFlow } from '~/context' -import { warn } from '~/utils' type Injection = VueFlowStore | null | undefined type Scope = (EffectScope & { vueFlowId: string }) | undefined diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index cf8a1e72a..62aa0ef59 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -58,6 +58,8 @@ export { */ export { applyChanges, applyEdgeChanges, applyNodeChanges } from './utils/changes' +export { Storage as GlobalVueFlowStorage } from './utils/storage' + export { defaultEdgeTypes, defaultNodeTypes } from './store/state' export { VueFlow as VueFlowInjection, NodeId as NodeIdInjection } from './context' diff --git a/packages/core/src/storage/index.ts b/packages/core/src/storage/index.ts deleted file mode 100644 index 69b61ecc4..000000000 --- a/packages/core/src/storage/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './storage' diff --git a/packages/core/src/storage/storage.ts b/packages/core/src/utils/storage.ts similarity index 100% rename from packages/core/src/storage/storage.ts rename to packages/core/src/utils/storage.ts From 04eb4c270f8db0e7824d554983d5eec5e717b3f3 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:17:16 +0200 Subject: [PATCH 17/78] feat(core): add option to set global config --- packages/core/src/utils/storage.ts | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts index c539c178d..b1a9e120e 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/storage.ts @@ -5,9 +5,12 @@ import { useActions, useGetters, useState } from '~/store' * Stores all currently created store instances */ export class Storage { + static instance: Storage + public currentId = 0 + public flows = new Map() - static instance: Storage + private hooks = { beforeCreate: createEventHook<[string, FlowOptions | undefined]>(), created: createEventHook(), @@ -15,6 +18,9 @@ export class Storage { destroyed: createEventHook(), } + /** Used by each store instance that is created as default values for store */ + public config: Partial> = {} + public static getInstance(): Storage { if (!Storage.instance) { Storage.instance = new Storage() @@ -35,9 +41,12 @@ export class Storage { return this.flows.delete(id) } - public create(id: string, preloadedState?: FlowOptions): VueFlowStore { - this.hooks.beforeCreate.trigger([id, preloadedState]) - const state: State = useState(preloadedState) + public create(id: string, initialOptions?: FlowOptions): VueFlowStore { + const initialState = { ...this.config, ...initialOptions } + + this.hooks.beforeCreate.trigger([id, initialState]) + + const state: State = useState(initialState) const reactiveState = reactive(state) @@ -58,10 +67,10 @@ export class Storage { actions.setState(reactiveState) - if (preloadedState) { - if (preloadedState.modelValue) actions.setElements(preloadedState.modelValue) - if (preloadedState.nodes) actions.setNodes(preloadedState.nodes) - if (preloadedState.edges) actions.setEdges(preloadedState.edges) + if (initialState) { + if (initialState.modelValue) actions.setElements(initialState.modelValue) + if (initialState.nodes) actions.setNodes(initialState.nodes) + if (initialState.edges) actions.setEdges(initialState.edges) } const flow: VueFlowStore = { @@ -99,4 +108,8 @@ export class Storage { }), ) } + + public setConfig(options: Partial>) { + this.config = options + } } From 5ea5588da2856af0e5a9e4466f865b31b362b15a Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:34:56 +0200 Subject: [PATCH 18/78] feat(core): add `createVueFlow` helper --- packages/core/src/index.ts | 2 +- packages/core/src/utils/storage.ts | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 62aa0ef59..11e10bedf 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -58,7 +58,7 @@ export { */ export { applyChanges, applyEdgeChanges, applyNodeChanges } from './utils/changes' -export { Storage as GlobalVueFlowStorage } from './utils/storage' +export { Storage as GlobalVueFlowStorage, createVueFlow } from './utils/storage' export { defaultEdgeTypes, defaultNodeTypes } from './store/state' diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts index b1a9e120e..64f68fd15 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/storage.ts @@ -2,7 +2,13 @@ import type { FlowOptions, Plugin, State, VueFlowStore } from '~/types' import { useActions, useGetters, useState } from '~/store' /** - * Stores all currently created store instances + * Global Storage + * + * Stores all store instances and provides access to them + * + * Holds global config that is passed to all store instances + * + * Provides hooks for plugins to access the store */ export class Storage { static instance: Storage @@ -98,7 +104,11 @@ export class Storage { return `vue-flow-${this.currentId++}` } - public install(plugins: Plugin[]) { + /** + * Helper to install plugin + * @param plugins + */ + public use(plugins: Plugin[]) { plugins.forEach((plugin) => plugin({ onBeforeCreate: this.hooks.beforeCreate.on, @@ -107,9 +117,25 @@ export class Storage { destroyed: this.hooks.destroyed.on, }), ) + + return this } + /** + * Helper to set global config + * @param options + */ public setConfig(options: Partial>) { this.config = options + + return this } } + +export const createVueFlow = (options: Omit, 'id'>) => { + const storage = Storage.getInstance() + + storage.setConfig(options) + + return storage +} From ed09a0a7955905b791d3f264a5a9217d2904f107 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:34:56 +0200 Subject: [PATCH 19/78] chore(core): optional arg --- packages/core/src/utils/storage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts index 64f68fd15..0453c6b12 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/storage.ts @@ -132,7 +132,7 @@ export class Storage { } } -export const createVueFlow = (options: Omit, 'id'>) => { +export const createVueFlow = (options: Omit, 'id'> = {}) => { const storage = Storage.getInstance() storage.setConfig(options) From 20d026977083d9134e3f4d9e1a6ea6650e711f6c Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Thu, 13 Oct 2022 16:26:44 +0200 Subject: [PATCH 20/78] chore(core): plugin hook name --- packages/core/src/types/plugins.ts | 2 +- packages/core/src/utils/storage.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/types/plugins.ts b/packages/core/src/types/plugins.ts index 2366a24b5..ab87e5dfd 100644 --- a/packages/core/src/types/plugins.ts +++ b/packages/core/src/types/plugins.ts @@ -3,7 +3,7 @@ import type { FlowOptions } from './flow' import type { VueFlowStore } from './store' export interface PluginHooks { - onBeforeCreate: EventHookOn<[string, FlowOptions | undefined]> + beforeCreate: EventHookOn<[string, FlowOptions | undefined]> created: EventHookOn beforeDestroy: EventHookOn destroyed: EventHookOn diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts index 0453c6b12..add62600f 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/storage.ts @@ -111,7 +111,7 @@ export class Storage { public use(plugins: Plugin[]) { plugins.forEach((plugin) => plugin({ - onBeforeCreate: this.hooks.beforeCreate.on, + beforeCreate: this.hooks.beforeCreate.on, created: this.hooks.created.on, beforeDestroy: this.hooks.beforeDestroy.on, destroyed: this.hooks.destroyed.on, From 3e12dfd8487bceba4e22d781016d591647b4c9a9 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Tue, 18 Oct 2022 21:36:01 +0200 Subject: [PATCH 21/78] refactor(core): rename `Storage` to `VueFlowApp` --- .changeset/weak-points-whisper.md | 4 ++-- packages/core/src/composables/useVueFlow.ts | 2 +- packages/core/src/index.ts | 2 +- .../src/utils/{storage.ts => vueFlowApp.ts} | 23 +++++++++---------- 4 files changed, 15 insertions(+), 16 deletions(-) rename packages/core/src/utils/{storage.ts => vueFlowApp.ts} (88%) diff --git a/.changeset/weak-points-whisper.md b/.changeset/weak-points-whisper.md index d527e6c2d..2cc1ce81a 100644 --- a/.changeset/weak-points-whisper.md +++ b/.changeset/weak-points-whisper.md @@ -3,11 +3,11 @@ 'vueflow': minor --- -Add plugin API to Vue Flow Storage +Add plugin API to Vue Flow App ## Summary -- Add plugin API to Vue Flow Storage +- Add plugin API to Vue Flow App - Allows to add plugins that can add custom functionality to the store - Provides hooks for - `beforeCreate` - before a store is created diff --git a/packages/core/src/composables/useVueFlow.ts b/packages/core/src/composables/useVueFlow.ts index a6fd09824..4b75bccaa 100644 --- a/packages/core/src/composables/useVueFlow.ts +++ b/packages/core/src/composables/useVueFlow.ts @@ -11,7 +11,7 @@ type Scope = (EffectScope & { vueFlowId: string }) | undefined // todo: maybe replace the storage with a context based solution; This would break calling useVueFlow outside a setup function though, which should be fine export function useVueFlow(options?: FlowProps): VueFlowStore { - const storage = Storage.getInstance() + const storage = createVueFlow() const scope = getCurrentScope() as Scope diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 11e10bedf..8e8afd64c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -58,7 +58,7 @@ export { */ export { applyChanges, applyEdgeChanges, applyNodeChanges } from './utils/changes' -export { Storage as GlobalVueFlowStorage, createVueFlow } from './utils/storage' +export { VueFlowApp, createVueFlow } from './utils/vueFlowApp' export { defaultEdgeTypes, defaultNodeTypes } from './store/state' diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/vueFlowApp.ts similarity index 88% rename from packages/core/src/utils/storage.ts rename to packages/core/src/utils/vueFlowApp.ts index add62600f..47651b8f5 100644 --- a/packages/core/src/utils/storage.ts +++ b/packages/core/src/utils/vueFlowApp.ts @@ -2,7 +2,7 @@ import type { FlowOptions, Plugin, State, VueFlowStore } from '~/types' import { useActions, useGetters, useState } from '~/store' /** - * Global Storage + * Global Vue Flow App * * Stores all store instances and provides access to them * @@ -10,8 +10,8 @@ import { useActions, useGetters, useState } from '~/store' * * Provides hooks for plugins to access the store */ -export class Storage { - static instance: Storage +export class VueFlowApp { + static instance: VueFlowApp public currentId = 0 @@ -27,12 +27,12 @@ export class Storage { /** Used by each store instance that is created as default values for store */ public config: Partial> = {} - public static getInstance(): Storage { - if (!Storage.instance) { - Storage.instance = new Storage() + public static getInstance(): VueFlowApp { + if (!VueFlowApp.instance) { + VueFlowApp.instance = new VueFlowApp() } - return Storage.instance + return VueFlowApp.instance } public set(id: string, flow: VueFlowStore) { @@ -106,7 +106,6 @@ export class Storage { /** * Helper to install plugin - * @param plugins */ public use(plugins: Plugin[]) { plugins.forEach((plugin) => @@ -132,10 +131,10 @@ export class Storage { } } -export const createVueFlow = (options: Omit, 'id'> = {}) => { - const storage = Storage.getInstance() +export const createVueFlow = (options?: Omit, 'id'>) => { + const app = VueFlowApp.getInstance() - storage.setConfig(options) + if (options) app.setConfig(options) - return storage + return app } From 8d9445d43a537c4176854a05f729e8fff037e287 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Tue, 18 Oct 2022 21:36:20 +0200 Subject: [PATCH 22/78] refactor(core): only install one plugin per `use` call --- packages/core/src/utils/vueFlowApp.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/core/src/utils/vueFlowApp.ts b/packages/core/src/utils/vueFlowApp.ts index 47651b8f5..119ea06da 100644 --- a/packages/core/src/utils/vueFlowApp.ts +++ b/packages/core/src/utils/vueFlowApp.ts @@ -107,15 +107,13 @@ export class VueFlowApp { /** * Helper to install plugin */ - public use(plugins: Plugin[]) { - plugins.forEach((plugin) => - plugin({ - beforeCreate: this.hooks.beforeCreate.on, - created: this.hooks.created.on, - beforeDestroy: this.hooks.beforeDestroy.on, - destroyed: this.hooks.destroyed.on, - }), - ) + public use(plugin: Plugin) { + plugin({ + beforeCreate: this.hooks.beforeCreate.on, + created: this.hooks.created.on, + beforeDestroy: this.hooks.beforeDestroy.on, + destroyed: this.hooks.destroyed.on, + }) return this } From 346508fcf46e6b9e74d726c2f34699a1abc31bc0 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 22:29:23 +0100 Subject: [PATCH 23/78] tests: add tests for plugin api install --- e2e/cypress/component/4-plugins/install.cy.ts | 33 +++++++++++++++++++ e2e/cypress/component/4-plugins/shims.d.ts | 8 +++++ 2 files changed, 41 insertions(+) create mode 100644 e2e/cypress/component/4-plugins/install.cy.ts create mode 100644 e2e/cypress/component/4-plugins/shims.d.ts diff --git a/e2e/cypress/component/4-plugins/install.cy.ts b/e2e/cypress/component/4-plugins/install.cy.ts new file mode 100644 index 000000000..4b0245aa2 --- /dev/null +++ b/e2e/cypress/component/4-plugins/install.cy.ts @@ -0,0 +1,33 @@ +import type { Plugin } from '@vue-flow/core' +import { createVueFlow, useVueFlow } from '@vue-flow/core' + +import { getElements } from '../../utils' + +const { nodes, edges } = getElements() + +const testPlugin: Plugin = (hooks) => { + hooks.created((store) => { + store.testProp = 'test' + store.testAction = () => true + }) +} + +createVueFlow().use(testPlugin) + +describe('Install test plugin', () => { + const store = useVueFlow({ id: 'test' }) + + beforeEach(() => { + cy.vueFlow({ + modelValue: [...nodes, ...edges], + }) + }) + + it('has test prop', () => { + expect(store.testProp).to.equal('test') + }) + + it('has test action', () => { + expect(store.testAction()).to.equal(true) + }) +}) diff --git a/e2e/cypress/component/4-plugins/shims.d.ts b/e2e/cypress/component/4-plugins/shims.d.ts new file mode 100644 index 000000000..eab05e5f9 --- /dev/null +++ b/e2e/cypress/component/4-plugins/shims.d.ts @@ -0,0 +1,8 @@ +import * as VF from '@vue-flow/core' + +declare module '@vue-flow/core' { + interface StoreBase { + testProp: string + testAction: () => boolean + } +} From 9db136809e09cad4f69e265e6189417d7358a436 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:50:09 +0200 Subject: [PATCH 24/78] chore(core): move `Storage` class to utils dir --- packages/core/src/utils/storage.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/core/src/utils/storage.ts diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts new file mode 100644 index 000000000..e69de29bb From e00547e9f53400b9da24b08944d312124534b5d8 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Tue, 18 Oct 2022 21:36:01 +0200 Subject: [PATCH 25/78] refactor(core): rename `Storage` to `VueFlowApp` --- packages/core/src/utils/storage.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 packages/core/src/utils/storage.ts diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts deleted file mode 100644 index e69de29bb..000000000 From e2ee96c2728540df853a6a71026f6841d8ea18cf Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:03:03 +0200 Subject: [PATCH 26/78] feat(plugins): add screenshot plugin --- packages/plugins/screenshot/README.md | 56 ++++++++++++ packages/plugins/screenshot/package.json | 47 ++++++++++ packages/plugins/screenshot/src/index.ts | 3 + packages/plugins/screenshot/src/screenshot.ts | 86 +++++++++++++++++++ packages/plugins/screenshot/src/store.ts | 7 ++ packages/plugins/screenshot/src/types.ts | 11 +++ packages/plugins/screenshot/tsconfig.json | 31 +++++++ packages/plugins/screenshot/vite.config.ts | 35 ++++++++ 8 files changed, 276 insertions(+) create mode 100644 packages/plugins/screenshot/README.md create mode 100644 packages/plugins/screenshot/package.json create mode 100644 packages/plugins/screenshot/src/index.ts create mode 100644 packages/plugins/screenshot/src/screenshot.ts create mode 100644 packages/plugins/screenshot/src/store.ts create mode 100644 packages/plugins/screenshot/src/types.ts create mode 100644 packages/plugins/screenshot/tsconfig.json create mode 100644 packages/plugins/screenshot/vite.config.ts diff --git a/packages/plugins/screenshot/README.md b/packages/plugins/screenshot/README.md new file mode 100644 index 000000000..494c0409f --- /dev/null +++ b/packages/plugins/screenshot/README.md @@ -0,0 +1,56 @@ +# Vue Flow: Plugin Screenshot + +This package contains a simple Screenshot plugin that can be used with Vue Flow. +Simply install the plugin onto your Vue Flow App and you can start using the composable to +screenshot your graph. + +## 🛠 Setup + +```bash +# install +$ yarn add @vue-flow/plugin-screenshot + +# or +$ npm i --save @vue-flow/plugin-screenshot +``` + +## 🎮 Quickstart + +- Install the plugin + +```ts +// main.ts or your app entry point +import { createVueFlow } from '@vue-flow/core' +import { PluginScreenshot } from '@vue-flow/plugin-screenshot' + +const vueFlowApp = createVueFlow() + +vueFlowApp.use(PluginScreenshot) +``` + +- Attach the handlers + +```vue + + +``` diff --git a/packages/plugins/screenshot/package.json b/packages/plugins/screenshot/package.json new file mode 100644 index 000000000..b774e2e83 --- /dev/null +++ b/packages/plugins/screenshot/package.json @@ -0,0 +1,47 @@ +{ + "name": "@vue-flow/plugin-screenshot", + "version": "0.0.1", + "private": false, + "license": "MIT", + "author": "Burak Cakmakoglu<78412429+bcakmakoglu@users.noreply.github.com>", + "repository": { + "type": "git", + "url": "git+https://github.com/bcakmakoglu/vue-flow/packages/plugins/screenshot" + }, + "homepage": "https://github.com/bcakmakoglu/vue-flow#readme", + "bugs": { + "url": "https://github.com/bcakmakoglu/vue-flow/issues" + }, + "main": "./dist/vue-flow-plugin-screenshot.cjs.js", + "module": "./dist/vue-flow-plugin-screenshot.es.js", + "types": "./dist/index.d.ts", + "unpkg": "./dist/vue-flow-plugin-screenshot.iife.js", + "jsdelivr": "./dist/vue-flow-plugin-screenshot.iife.js", + "files": [ + "dist" + ], + "sideEffects": false, + "scripts": { + "build": "vite build", + "types": "tsc && shx rm -rf tmp", + "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../.gitignore .", + "lint:dist": "eslint --ext \".ts,.tsx\" -c .eslintrc.js --fix ./dist", + "test": "exit 0" + }, + "peerDependencies": { + "@vue-flow/core": "^1.0.0", + "vue": "^3.2.37" + }, + "dependencies": { + "@vueuse/core": "^9.3.1", + "html-to-image": "^1.10.8" + }, + "devDependencies": { + "@vue-flow/core": "workspace:*", + "vite": "^2.9.15" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/plugins/screenshot/src/index.ts b/packages/plugins/screenshot/src/index.ts new file mode 100644 index 000000000..005f4b607 --- /dev/null +++ b/packages/plugins/screenshot/src/index.ts @@ -0,0 +1,3 @@ +import './store' +export * from './screenshot' +export * from './types' diff --git a/packages/plugins/screenshot/src/screenshot.ts b/packages/plugins/screenshot/src/screenshot.ts new file mode 100644 index 000000000..a0426b513 --- /dev/null +++ b/packages/plugins/screenshot/src/screenshot.ts @@ -0,0 +1,86 @@ +import type { Plugin, VueFlowStore } from '@vue-flow/core' +import { toJpeg as ElToJpg, toPng as ElToPng } from 'html-to-image' +import { useVueFlow } from '@vue-flow/core' +import { ref } from 'vue' +import type { ImageType, UseScreenshotState } from './types' + +const createScreenshotState = (store: VueFlowStore): UseScreenshotState => { + const dataUrl = ref('') + const imgType = ref('jpeg') + const error = ref() + + async function screenshot(type: ImageType = 'jpeg', fileName = 'vue-flow-screenshot') { + let data + + switch (type) { + case 'jpeg': + data = await toJpeg() + break + case 'png': + data = await toPng() + break + default: + data = await toJpeg() + break + } + + // immediately download the image if shouldDownload is true + if (!!fileName && fileName !== '') download(fileName) + + return data + } + + function toJpeg() { + error.value = null + + return ElToJpg(store.vueFlowRef.value, { quality: 0.95 }) + .then((data) => { + dataUrl.value = data + imgType.value = 'jpeg' + return data + }) + .catch((error) => { + error.value = error + throw new Error(error) + }) + } + + function toPng() { + error.value = null + + return ElToPng(store.vueFlowRef.value, { quality: 0.95 }) + .then((data) => { + dataUrl.value = data + imgType.value = 'png' + return data + }) + .catch((error) => { + error.value = error + throw new Error(error) + }) + } + + function download(fileName: string) { + const link = document.createElement('a') + link.download = `${fileName}.${imgType.value}` + link.href = dataUrl.value + link.click() + } + + return { + screenshot, + download, + dataUrl, + error, + } +} + +export const PluginScreenshot: Plugin = (hooks) => { + hooks.created((store) => { + store.screenshot = createScreenshotState(store) + }) +} + +export function useScreenshot() { + return useVueFlow().screenshot +} diff --git a/packages/plugins/screenshot/src/store.ts b/packages/plugins/screenshot/src/store.ts new file mode 100644 index 000000000..ce28aaa0e --- /dev/null +++ b/packages/plugins/screenshot/src/store.ts @@ -0,0 +1,7 @@ +import type { UseScreenshotState } from './types' + +declare module '@vue-flow/core' { + interface StoreBase { + screenshot: UseScreenshotState + } +} diff --git a/packages/plugins/screenshot/src/types.ts b/packages/plugins/screenshot/src/types.ts new file mode 100644 index 000000000..ab9fc3a0f --- /dev/null +++ b/packages/plugins/screenshot/src/types.ts @@ -0,0 +1,11 @@ +import type { Ref } from 'vue' + +export type ImageType = 'jpeg' | 'png' + +export interface UseScreenshotState { + // returns the data url of the screenshot + screenshot: (type?: ImageType, fileName?: string) => Promise + download: (fileName: string) => void + dataUrl: Ref + error: Ref +} diff --git a/packages/plugins/screenshot/tsconfig.json b/packages/plugins/screenshot/tsconfig.json new file mode 100644 index 000000000..e9fd0ac12 --- /dev/null +++ b/packages/plugins/screenshot/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "module": "ESNext", + "target": "es2017", + "lib": [ + "DOM", + "ESNext" + ], + "strict": true, + "esModuleInterop": true, + "incremental": false, + "skipLibCheck": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "noUnusedLocals": false, + "strictNullChecks": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationDir": "./dist", + "emitDeclarationOnly": true, + "types": [], + }, + "include": [ + "./src", + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/packages/plugins/screenshot/vite.config.ts b/packages/plugins/screenshot/vite.config.ts new file mode 100644 index 000000000..1c3597abe --- /dev/null +++ b/packages/plugins/screenshot/vite.config.ts @@ -0,0 +1,35 @@ +import { resolve } from 'path' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + resolve: { + extensions: ['.ts'], + }, + build: { + emptyOutDir: false, + lib: { + formats: ['es', 'cjs', 'iife'], + entry: resolve(__dirname, 'src/index.ts'), + fileName: 'vue-flow-plugin-screenshot', + name: 'vueFlowPluginScreenshot', + }, + rollupOptions: { + // make sure to externalize deps that shouldn't be bundled + // into your library + external: ['vue', '@vue-flow/core'], + output: { + dir: './dist', + // Provide global variables to use in the UMD build + // for externalized deps + globals: { + 'vue': 'Vue', + '@vue-flow/core': 'VueFlow', + }, + }, + }, + }, + optimizeDeps: { + include: ['vue', '@vueuse/core'], + }, +}) From fe8a68dac8b193ea3e13b278ceac9906029bcda5 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:17:08 +0200 Subject: [PATCH 27/78] chore: add changeset --- .changeset/wild-carrots-occur.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wild-carrots-occur.md diff --git a/.changeset/wild-carrots-occur.md b/.changeset/wild-carrots-occur.md new file mode 100644 index 000000000..f56c9b056 --- /dev/null +++ b/.changeset/wild-carrots-occur.md @@ -0,0 +1,5 @@ +--- +'@vue-flow/core': minor +--- + +Add screenshot plugin to easily create an image of the graph From 2f08cb63c13e7a223493623804370d2b837a4f65 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:50:50 +0200 Subject: [PATCH 28/78] chore: update readme --- .changeset/wild-carrots-occur.md | 4 ++-- packages/plugins/screenshot/README.md | 6 +++++- pnpm-workspace.yaml | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.changeset/wild-carrots-occur.md b/.changeset/wild-carrots-occur.md index f56c9b056..c668e355f 100644 --- a/.changeset/wild-carrots-occur.md +++ b/.changeset/wild-carrots-occur.md @@ -1,5 +1,5 @@ --- -'@vue-flow/core': minor +'@vue-flow/plugin-screenshot': major --- -Add screenshot plugin to easily create an image of the graph +Add screenshot plugin pkg to create a downloadable image of the graph diff --git a/packages/plugins/screenshot/README.md b/packages/plugins/screenshot/README.md index 494c0409f..9fa31fad5 100644 --- a/packages/plugins/screenshot/README.md +++ b/packages/plugins/screenshot/README.md @@ -50,7 +50,11 @@ const onClick = async () => { ``` diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9dff65600..188f11e03 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,7 @@ packages: + - examples/* - packages/* + - packages/plugins/* - tooling/* - - examples/* - tests - docs From 2634c9a268e5106794fab431106f30b29eba0dd2 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 22:21:00 +0100 Subject: [PATCH 29/78] chore(plugins): correct gitignore path --- packages/plugins/screenshot/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/screenshot/package.json b/packages/plugins/screenshot/package.json index b774e2e83..388aa5924 100644 --- a/packages/plugins/screenshot/package.json +++ b/packages/plugins/screenshot/package.json @@ -24,7 +24,7 @@ "scripts": { "build": "vite build", "types": "tsc && shx rm -rf tmp", - "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../.gitignore .", + "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../../.gitignore .", "lint:dist": "eslint --ext \".ts,.tsx\" -c .eslintrc.js --fix ./dist", "test": "exit 0" }, From 171200dd15f2ecf8a3df90e94100dea6e2c9641a Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:41:37 +0100 Subject: [PATCH 30/78] chore(plugins): remove optimizeDeps --- packages/plugins/screenshot/vite.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/plugins/screenshot/vite.config.ts b/packages/plugins/screenshot/vite.config.ts index 1c3597abe..f95ccab0c 100644 --- a/packages/plugins/screenshot/vite.config.ts +++ b/packages/plugins/screenshot/vite.config.ts @@ -29,7 +29,4 @@ export default defineConfig({ }, }, }, - optimizeDeps: { - include: ['vue', '@vueuse/core'], - }, }) From 718eef51b9f1e046e67cba72e6f896d945b39a4d Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:42:05 +0100 Subject: [PATCH 31/78] examples: add screenshot example --- examples/vite/main.ts | 6 ++++ examples/vite/package.json | 1 + examples/vite/router.ts | 4 +++ .../vite/src/Screenshot/ScreenshotExample.vue | 30 +++++++++++++++++++ examples/vite/vite.config.ts | 2 +- 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 examples/vite/src/Screenshot/ScreenshotExample.vue diff --git a/examples/vite/main.ts b/examples/vite/main.ts index 6d8604e29..ed9f44171 100644 --- a/examples/vite/main.ts +++ b/examples/vite/main.ts @@ -1,9 +1,15 @@ import { createApp } from 'vue' +import { createVueFlow } from '@vue-flow/core' +import { PluginScreenshot } from '@vue-flow/plugin-screenshot' import './index.css' import { createPinia } from 'pinia' import App from './App.vue' import { router } from './router' +const vueFlowApp = createVueFlow() + +vueFlowApp.use(PluginScreenshot) + const app = createApp(App) app.config.performance = true diff --git a/examples/vite/package.json b/examples/vite/package.json index bee1a6e69..1a7d5744e 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -13,6 +13,7 @@ "@vue-flow/minimap": "workspace:*", "@vue-flow/node-resizer": "workspace:*", "@vue-flow/node-toolbar": "workspace:*", + "@vue-flow/plugin-screenshot": "workspace:*", "pinia": "^2.0.35", "vueflow": "workspace:*" }, diff --git a/examples/vite/router.ts b/examples/vite/router.ts index 308fc59f2..6f68066c1 100644 --- a/examples/vite/router.ts +++ b/examples/vite/router.ts @@ -114,6 +114,10 @@ export const routes: RouterOptions['routes'] = [ path: '/nesting', component: () => import('./src/Nesting/Nesting.vue'), }, + { + path: '/screenshot', + component: () => import('./src/Screenshot/ScreenshotExample.vue'), + }, { path: '/rgb', component: () => import('./src/RGBFlow/RGBFlow.vue'), diff --git a/examples/vite/src/Screenshot/ScreenshotExample.vue b/examples/vite/src/Screenshot/ScreenshotExample.vue new file mode 100644 index 000000000..cb5da4eee --- /dev/null +++ b/examples/vite/src/Screenshot/ScreenshotExample.vue @@ -0,0 +1,30 @@ + + + diff --git a/examples/vite/vite.config.ts b/examples/vite/vite.config.ts index 954ecdf14..46e3c821c 100644 --- a/examples/vite/vite.config.ts +++ b/examples/vite/vite.config.ts @@ -16,7 +16,7 @@ export default defineConfig({ vueTypes(), svgLoader(), AutoImport({ - imports: ['vue', '@vueuse/core', 'vue/macros'], + imports: ['vue', '@vueuse/core'], dts: resolve('src/auto-imports.d.ts'), }), ], From 2b368d5bc7a72af990716e8e1d70849d14130f0e Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Wed, 19 Oct 2022 00:46:38 +0200 Subject: [PATCH 32/78] feat(plugins): add dagre layout plugin --- .changeset/slimy-seas-check.md | 5 +++ packages/plugins/dagre/README.md | 52 +++++++++++++++++++++++++++ packages/plugins/dagre/package.json | 47 ++++++++++++++++++++++++ packages/plugins/dagre/src/index.ts | 3 ++ packages/plugins/dagre/src/layout.ts | 46 ++++++++++++++++++++++++ packages/plugins/dagre/src/store.ts | 7 ++++ packages/plugins/dagre/src/types.ts | 8 +++++ packages/plugins/dagre/tsconfig.json | 31 ++++++++++++++++ packages/plugins/dagre/vite.config.ts | 35 ++++++++++++++++++ 9 files changed, 234 insertions(+) create mode 100644 .changeset/slimy-seas-check.md create mode 100644 packages/plugins/dagre/README.md create mode 100644 packages/plugins/dagre/package.json create mode 100644 packages/plugins/dagre/src/index.ts create mode 100644 packages/plugins/dagre/src/layout.ts create mode 100644 packages/plugins/dagre/src/store.ts create mode 100644 packages/plugins/dagre/src/types.ts create mode 100644 packages/plugins/dagre/tsconfig.json create mode 100644 packages/plugins/dagre/vite.config.ts diff --git a/.changeset/slimy-seas-check.md b/.changeset/slimy-seas-check.md new file mode 100644 index 000000000..400635d98 --- /dev/null +++ b/.changeset/slimy-seas-check.md @@ -0,0 +1,5 @@ +--- +'@vue-flow/plugin-dagre': major +--- + +Add dagre layout plugin pkg diff --git a/packages/plugins/dagre/README.md b/packages/plugins/dagre/README.md new file mode 100644 index 000000000..5dcbc4654 --- /dev/null +++ b/packages/plugins/dagre/README.md @@ -0,0 +1,52 @@ +# Vue Flow: Plugin Dagre + +This package contains a simple Dagre Layout plugin that can be used with Vue Flow. +Simply install the plugin onto your Vue Flow App and you can start using the composable to +layout your graph. + +## 🛠 Setup + +```bash +# install +$ yarn add @vue-flow/plugin-dagre + +# or +$ npm i --save @vue-flow/plugin-dagre +``` + +## 🎮 Quickstart + +- Install the plugin + +```ts +// main.ts or your app entry point +import { createVueFlow } from '@vue-flow/core' +import { PluginScreenshot } from '@vue-flow/plugin-dagre' + +const vueFlowApp = createVueFlow() + +vueFlowApp.use(PluginScreenshot) +``` + +- Attach the handlers + +```vue + + +``` diff --git a/packages/plugins/dagre/package.json b/packages/plugins/dagre/package.json new file mode 100644 index 000000000..2883ab80c --- /dev/null +++ b/packages/plugins/dagre/package.json @@ -0,0 +1,47 @@ +{ + "name": "@vue-flow/plugin-dagre", + "version": "0.0.1", + "private": false, + "license": "MIT", + "author": "Burak Cakmakoglu<78412429+bcakmakoglu@users.noreply.github.com>", + "repository": { + "type": "git", + "url": "git+https://github.com/bcakmakoglu/vue-flow/packages/plugins/dagre" + }, + "homepage": "https://github.com/bcakmakoglu/vue-flow#readme", + "bugs": { + "url": "https://github.com/bcakmakoglu/vue-flow/issues" + }, + "main": "./dist/vue-flow-plugin-dagre.cjs.js", + "module": "./dist/vue-flow-plugin-dagre.es.js", + "types": "./dist/index.d.ts", + "unpkg": "./dist/vue-flow-plugin-dagre.iife.js", + "jsdelivr": "./dist/vue-flow-plugin-dagre.iife.js", + "files": [ + "dist" + ], + "sideEffects": false, + "scripts": { + "build": "vite build", + "types": "tsc && shx rm -rf tmp", + "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../.gitignore .", + "lint:dist": "eslint --ext \".ts,.tsx\" -c .eslintrc.js --fix ./dist", + "test": "exit 0" + }, + "peerDependencies": { + "@vue-flow/core": "^1.0.0", + "vue": "^3.2.37" + }, + "dependencies": { + "dagre": "^0.8.5" + }, + "devDependencies": { + "@types/dagre": "^0.7.48", + "@vue-flow/core": "workspace:*", + "vite": "^2.9.15" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + } +} diff --git a/packages/plugins/dagre/src/index.ts b/packages/plugins/dagre/src/index.ts new file mode 100644 index 000000000..005f4b607 --- /dev/null +++ b/packages/plugins/dagre/src/index.ts @@ -0,0 +1,3 @@ +import './store' +export * from './screenshot' +export * from './types' diff --git a/packages/plugins/dagre/src/layout.ts b/packages/plugins/dagre/src/layout.ts new file mode 100644 index 000000000..9e81f690b --- /dev/null +++ b/packages/plugins/dagre/src/layout.ts @@ -0,0 +1,46 @@ +import type { Plugin, VueFlowStore } from '@vue-flow/core' +import { Position, useVueFlow } from '@vue-flow/core' +import dagre from 'dagre' +import type { Direction } from './types' + +const createDagreState = (store: VueFlowStore) => { + const dagreGraph = new dagre.graphlib.Graph() + dagreGraph.setDefaultEdgeLabel(() => ({})) + + function layout(direction: Direction) { + const isHorizontal = direction === 'LR' || direction === 'RL' + dagreGraph.setGraph({ rankdir: direction }) + + store.nodes.value.forEach((node) => { + dagreGraph.setNode(node.id, { width: node.dimensions.width, height: node.dimensions.height }) + }) + + store.edges.value.forEach((edge) => { + dagreGraph.setEdge(edge.source, edge.target) + }) + + dagre.layout(dagreGraph) + + store.nodes.value.forEach((node) => { + const nodeWithPosition = dagreGraph.node(node.id) + node.targetPosition = isHorizontal ? Position.Left : Position.Top + node.sourcePosition = isHorizontal ? Position.Right : Position.Bottom + node.position = { x: nodeWithPosition.x, y: nodeWithPosition.y } + }) + } + + return { + dagreGraph, + layout, + } +} + +export const PluginDagreLayout: Plugin = (hooks) => { + hooks.created((store) => { + store.dagre = createDagreState(store) + }) +} + +export function useDagreLayout() { + return useVueFlow().dagre +} diff --git a/packages/plugins/dagre/src/store.ts b/packages/plugins/dagre/src/store.ts new file mode 100644 index 000000000..8ffcf69ee --- /dev/null +++ b/packages/plugins/dagre/src/store.ts @@ -0,0 +1,7 @@ +import type { UseDagreState } from './types' + +declare module '@vue-flow/core' { + interface StoreBase { + dagre: UseDagreState + } +} diff --git a/packages/plugins/dagre/src/types.ts b/packages/plugins/dagre/src/types.ts new file mode 100644 index 000000000..a6b997171 --- /dev/null +++ b/packages/plugins/dagre/src/types.ts @@ -0,0 +1,8 @@ +import type dagre from 'dagre' + +export type Direction = 'TB' | 'BT' | 'LR' | 'RL' + +export interface UseDagreState { + layout: (direction: Direction) => void + dagreGraph: dagre.graphlib.Graph +} diff --git a/packages/plugins/dagre/tsconfig.json b/packages/plugins/dagre/tsconfig.json new file mode 100644 index 000000000..e9fd0ac12 --- /dev/null +++ b/packages/plugins/dagre/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "module": "ESNext", + "target": "es2017", + "lib": [ + "DOM", + "ESNext" + ], + "strict": true, + "esModuleInterop": true, + "incremental": false, + "skipLibCheck": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "noUnusedLocals": false, + "strictNullChecks": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationDir": "./dist", + "emitDeclarationOnly": true, + "types": [], + }, + "include": [ + "./src", + ], + "exclude": [ + "node_modules", + "dist" + ] +} diff --git a/packages/plugins/dagre/vite.config.ts b/packages/plugins/dagre/vite.config.ts new file mode 100644 index 000000000..4282b90db --- /dev/null +++ b/packages/plugins/dagre/vite.config.ts @@ -0,0 +1,35 @@ +import { resolve } from 'path' +import { defineConfig } from 'vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + resolve: { + extensions: ['.ts'], + }, + build: { + emptyOutDir: false, + lib: { + formats: ['es', 'cjs', 'iife'], + entry: resolve(__dirname, 'src/index.ts'), + fileName: 'vue-flow-plugin-dagre', + name: 'vueFlowPluginDagre', + }, + rollupOptions: { + // make sure to externalize deps that shouldn't be bundled + // into your library + external: ['vue', '@vue-flow/core'], + output: { + dir: './dist', + // Provide global variables to use in the UMD build + // for externalized deps + globals: { + 'vue': 'Vue', + '@vue-flow/core': 'VueFlow', + }, + }, + }, + }, + optimizeDeps: { + include: ['vue', '@vueuse/core'], + }, +}) From f19e55bf0597731c03ab12dc150ffc019b5289c0 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 22:19:59 +0100 Subject: [PATCH 33/78] chore(plugins): correct gitignore path --- packages/plugins/dagre/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/dagre/package.json b/packages/plugins/dagre/package.json index 2883ab80c..a8e15c85f 100644 --- a/packages/plugins/dagre/package.json +++ b/packages/plugins/dagre/package.json @@ -24,7 +24,7 @@ "scripts": { "build": "vite build", "types": "tsc && shx rm -rf tmp", - "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../.gitignore .", + "lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../../.gitignore .", "lint:dist": "eslint --ext \".ts,.tsx\" -c .eslintrc.js --fix ./dist", "test": "exit 0" }, From 925e30f1cb0be4336b478ec0fe8333af821e1d06 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Fri, 4 Nov 2022 22:31:09 +0100 Subject: [PATCH 34/78] chore(plugins): correct export path --- packages/plugins/dagre/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/dagre/src/index.ts b/packages/plugins/dagre/src/index.ts index 005f4b607..3fd82f7eb 100644 --- a/packages/plugins/dagre/src/index.ts +++ b/packages/plugins/dagre/src/index.ts @@ -1,3 +1,3 @@ import './store' -export * from './screenshot' +export * from './layout' export * from './types' From 106cf3bc43bc367e60ccaccdae1965dbc679554c Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sat, 5 Nov 2022 00:14:11 +0100 Subject: [PATCH 35/78] chore(plugins): exclude dagre from dagre plugin --- packages/plugins/dagre/README.md | 8 ++++---- packages/plugins/dagre/package.json | 6 +++--- packages/plugins/dagre/src/layout.ts | 6 +++--- packages/plugins/dagre/vite.config.ts | 6 ++---- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/plugins/dagre/README.md b/packages/plugins/dagre/README.md index 5dcbc4654..4c6234ddd 100644 --- a/packages/plugins/dagre/README.md +++ b/packages/plugins/dagre/README.md @@ -2,16 +2,16 @@ This package contains a simple Dagre Layout plugin that can be used with Vue Flow. Simply install the plugin onto your Vue Flow App and you can start using the composable to -layout your graph. +lay out your graph. ## 🛠 Setup ```bash -# install -$ yarn add @vue-flow/plugin-dagre +# install plugin & dagre (plugin does not include dagre) +$ yarn add @vue-flow/plugin-dagre dagre # or -$ npm i --save @vue-flow/plugin-dagre +$ npm i --save @vue-flow/plugin-dagre dagre ``` ## 🎮 Quickstart diff --git a/packages/plugins/dagre/package.json b/packages/plugins/dagre/package.json index a8e15c85f..c8a9415c6 100644 --- a/packages/plugins/dagre/package.json +++ b/packages/plugins/dagre/package.json @@ -30,14 +30,14 @@ }, "peerDependencies": { "@vue-flow/core": "^1.0.0", - "vue": "^3.2.37" - }, - "dependencies": { + "vue": "^3.2.37", "dagre": "^0.8.5" }, + "dependencies": {}, "devDependencies": { "@types/dagre": "^0.7.48", "@vue-flow/core": "workspace:*", + "dagre": "^0.8.5", "vite": "^2.9.15" }, "publishConfig": { diff --git a/packages/plugins/dagre/src/layout.ts b/packages/plugins/dagre/src/layout.ts index 9e81f690b..a96b044e4 100644 --- a/packages/plugins/dagre/src/layout.ts +++ b/packages/plugins/dagre/src/layout.ts @@ -1,10 +1,10 @@ import type { Plugin, VueFlowStore } from '@vue-flow/core' import { Position, useVueFlow } from '@vue-flow/core' -import dagre from 'dagre' +import { layout as dagreLayout, graphlib } from 'dagre' import type { Direction } from './types' const createDagreState = (store: VueFlowStore) => { - const dagreGraph = new dagre.graphlib.Graph() + const dagreGraph = new graphlib.Graph() dagreGraph.setDefaultEdgeLabel(() => ({})) function layout(direction: Direction) { @@ -19,7 +19,7 @@ const createDagreState = (store: VueFlowStore) => { dagreGraph.setEdge(edge.source, edge.target) }) - dagre.layout(dagreGraph) + dagreLayout(dagreGraph) store.nodes.value.forEach((node) => { const nodeWithPosition = dagreGraph.node(node.id) diff --git a/packages/plugins/dagre/vite.config.ts b/packages/plugins/dagre/vite.config.ts index 4282b90db..c46166e1a 100644 --- a/packages/plugins/dagre/vite.config.ts +++ b/packages/plugins/dagre/vite.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ rollupOptions: { // make sure to externalize deps that shouldn't be bundled // into your library - external: ['vue', '@vue-flow/core'], + external: ['vue', '@vue-flow/core', 'dagre'], output: { dir: './dist', // Provide global variables to use in the UMD build @@ -25,11 +25,9 @@ export default defineConfig({ globals: { 'vue': 'Vue', '@vue-flow/core': 'VueFlow', + 'dagre': 'Dagre', }, }, }, }, - optimizeDeps: { - include: ['vue', '@vueuse/core'], - }, }) From be8002d5dcfef8cfd5e8aa4e3fca80db55899d20 Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Sat, 5 Nov 2022 00:14:28 +0100 Subject: [PATCH 36/78] examples: use dagre plugin in layouting example --- examples/vite/main.ts | 5 +- examples/vite/package.json | 1 + .../vite/src/Layouting/LayoutingExample.vue | 57 ++++--------------- 3 files changed, 15 insertions(+), 48 deletions(-) diff --git a/examples/vite/main.ts b/examples/vite/main.ts index ed9f44171..0b4af92ea 100644 --- a/examples/vite/main.ts +++ b/examples/vite/main.ts @@ -1,17 +1,18 @@ import { createApp } from 'vue' import { createVueFlow } from '@vue-flow/core' +import { PluginDagreLayout } from '@vue-flow/plugin-dagre' import { PluginScreenshot } from '@vue-flow/plugin-screenshot' import './index.css' import { createPinia } from 'pinia' import App from './App.vue' import { router } from './router' +const app = createApp(App) const vueFlowApp = createVueFlow() +vueFlowApp.use(PluginDagreLayout) vueFlowApp.use(PluginScreenshot) -const app = createApp(App) - app.config.performance = true app.use(router) app.use(createPinia()) diff --git a/examples/vite/package.json b/examples/vite/package.json index 1a7d5744e..c1ad1a33a 100644 --- a/examples/vite/package.json +++ b/examples/vite/package.json @@ -13,6 +13,7 @@ "@vue-flow/minimap": "workspace:*", "@vue-flow/node-resizer": "workspace:*", "@vue-flow/node-toolbar": "workspace:*", + "@vue-flow/plugin-dagre": "workspace:*", "@vue-flow/plugin-screenshot": "workspace:*", "pinia": "^2.0.35", "vueflow": "workspace:*" diff --git a/examples/vite/src/Layouting/LayoutingExample.vue b/examples/vite/src/Layouting/LayoutingExample.vue index d7421925d..7fc6f2bef 100644 --- a/examples/vite/src/Layouting/LayoutingExample.vue +++ b/examples/vite/src/Layouting/LayoutingExample.vue @@ -1,57 +1,22 @@