diff --git a/packages/core/src/composables/useVueFlow.ts b/packages/core/src/composables/useVueFlow.ts index 4d08ab94..be8765b6 100644 --- a/packages/core/src/composables/useVueFlow.ts +++ b/packages/core/src/composables/useVueFlow.ts @@ -1,94 +1,10 @@ -import { toRefs, tryOnScopeDispose } from '@vueuse/core' +import { tryOnScopeDispose } from '@vueuse/core' import type { EffectScope } from 'vue' -import { computed, effectScope, getCurrentInstance, getCurrentScope, inject, provide, reactive, watch } from 'vue' +import { effectScope, getCurrentScope, inject, provide, watch } from 'vue' import type { EdgeChange, FlowOptions, NodeChange, VueFlowStore } from '../types' import { warn } from '../utils' -import { useActions, useGetters, useState } from '../store' import { VueFlow } from '../context' - -/** - * Stores all currently created store instances - */ -export class Storage { - public currentId = 0 - public flows = new Map() - static instance: Storage - - public static getInstance(): Storage { - // todo: this is just a workaround for now, in the next major this class won't exist and the state will be ctx-based (like React Provider) - const vueApp = getCurrentInstance()?.appContext.app - - const existingInstance = vueApp?.config.globalProperties.$vueFlowStorage - - Storage.instance = existingInstance ?? new Storage() - - if (vueApp) { - vueApp.config.globalProperties.$vueFlowStorage = Storage.instance - } - - 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 = useState() - - const reactiveState = reactive(state) - - const hooksOn = {} - for (const [n, h] of Object.entries(reactiveState.hooks)) { - const name = `on${n.charAt(0).toUpperCase() + n.slice(1)}` - hooksOn[name] = h.on - } - - const emits = {} - for (const [n, h] of Object.entries(reactiveState.hooks)) { - emits[n] = h.trigger - } - - // for lookup purposes - 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(id, reactiveState, nodeIds, edgeIds) - - actions.setState({ ...reactiveState, ...preloadedState }) - - 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++}` - } -} +import { Storage } from '../utils/storage' type Injection = VueFlowStore | null | undefined type Scope = (EffectScope & { vueFlowId: string }) | undefined diff --git a/packages/core/src/utils/storage.ts b/packages/core/src/utils/storage.ts new file mode 100644 index 00000000..dec182aa --- /dev/null +++ b/packages/core/src/utils/storage.ts @@ -0,0 +1,88 @@ +import { toRefs } from '@vueuse/core' +import { computed, getCurrentInstance, reactive } from 'vue' +import type { FlowOptions, 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 + + public static getInstance(): Storage { + // todo: this is just a workaround for now, in the next major this class won't exist and the state will be ctx-based (like React Provider) + const vueApp = getCurrentInstance()?.appContext.app + + const existingInstance = vueApp?.config.globalProperties.$vueFlowStorage ?? Storage.instance + + Storage.instance = existingInstance ?? new Storage() + + if (vueApp) { + vueApp.config.globalProperties.$vueFlowStorage = Storage.instance + } + + 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 = useState() + + const reactiveState = reactive(state) + + const hooksOn = {} + for (const [n, h] of Object.entries(reactiveState.hooks)) { + const name = `on${n.charAt(0).toUpperCase() + n.slice(1)}` + hooksOn[name] = h.on + } + + const emits = {} + for (const [n, h] of Object.entries(reactiveState.hooks)) { + emits[n] = h.trigger + } + + // for lookup purposes + 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(id, reactiveState, nodeIds, edgeIds) + + actions.setState({ ...reactiveState, ...preloadedState }) + + 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++}` + } +}