feat!: Add hooks to store
* For easier access and to avoid context issues with injections hooks are put into the store * hooks can be accessed and will emit events when the flow has bound its emit function to the hooks * useHooks and useStore are not exported anymore! Instead, useVueFlow is provided, which will return an instance of the current vue flow store * Rename NodeIdContextKey to NodeId * Add addElements function to store to add elements without having to re-set the whole store * use v-model for elements, re-set elements only if there's an actual change Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useHandle, useHooks, useStore } from '../../composables'
|
import { useHandle, useHooks, useStore } from '../../composables'
|
||||||
import { Position, ValidConnectionFunc } from '../../types'
|
import { Position, ValidConnectionFunc } from '../../types'
|
||||||
import { NodeIdContextKey } from '~/context'
|
import { NodeId } from '~/context'
|
||||||
|
|
||||||
interface HandleProps {
|
interface HandleProps {
|
||||||
id?: string
|
id?: string
|
||||||
@@ -20,7 +20,7 @@ const props = withDefaults(defineProps<HandleProps>(), {
|
|||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const hooks = useHooks()
|
const hooks = useHooks()
|
||||||
const nodeId = inject(NodeIdContextKey)!
|
const nodeId = inject(NodeId)!
|
||||||
|
|
||||||
const handler = useHandle()
|
const handler = useHandle()
|
||||||
const onMouseDownHandler = (event: MouseEvent) =>
|
const onMouseDownHandler = (event: MouseEvent) =>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable'
|
import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable'
|
||||||
import { useHooks, useStore } from '../../composables'
|
import { useHooks, useStore } from '../../composables'
|
||||||
import { Node, NodeType, SnapGrid } from '../../types'
|
import { Node, NodeType, SnapGrid } from '../../types'
|
||||||
import { NodeIdContextKey } from '~/context'
|
import { NodeId } from '~/context'
|
||||||
|
|
||||||
interface NodeProps {
|
interface NodeProps {
|
||||||
node: Node
|
node: Node
|
||||||
@@ -19,7 +19,7 @@ const props = withDefaults(defineProps<NodeProps>(), {
|
|||||||
|
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const hooks = useHooks()
|
const hooks = useHooks()
|
||||||
provide(NodeIdContextKey, props.node.id)
|
provide(NodeId, props.node.id)
|
||||||
|
|
||||||
const nodeElement = templateRef<HTMLDivElement>('node-element', null)
|
const nodeElement = templateRef<HTMLDivElement>('node-element', null)
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ export { default as useKeyPress } from './useKeyPress'
|
|||||||
export { default as useZoomPanHelper } from './useZoomPanHelper'
|
export { default as useZoomPanHelper } from './useZoomPanHelper'
|
||||||
export { default as useStore } from './useStore'
|
export { default as useStore } from './useStore'
|
||||||
export { default as useWindow } from './useWindow'
|
export { default as useWindow } from './useWindow'
|
||||||
export { default as useVueFlow } from './useVueFlow'
|
export { default as useVueFlow, initFlow } from './useVueFlow'
|
||||||
|
|||||||
+23
-21
@@ -1,8 +1,20 @@
|
|||||||
import { Connection, Edge, Elements, EmitFunc, FlowHooks, FlowTransform, Node, OnConnectStartParams, FlowInstance } from '~/types'
|
import useStore from './useStore'
|
||||||
|
import {
|
||||||
|
Connection,
|
||||||
|
Edge,
|
||||||
|
Elements,
|
||||||
|
EmitFunc,
|
||||||
|
FlowHooks,
|
||||||
|
FlowTransform,
|
||||||
|
Node,
|
||||||
|
OnConnectStartParams,
|
||||||
|
FlowInstance,
|
||||||
|
FlowEvents,
|
||||||
|
} from '~/types'
|
||||||
import { Hooks } from '~/context'
|
import { Hooks } from '~/context'
|
||||||
|
|
||||||
// flow event hooks
|
// flow event hooks
|
||||||
const hooks = (): FlowHooks => {
|
export const createHooks = (): FlowHooks => {
|
||||||
return {
|
return {
|
||||||
elementClick: createEventHook<{ event: MouseEvent; element: Node | Edge }>(),
|
elementClick: createEventHook<{ event: MouseEvent; element: Node | Edge }>(),
|
||||||
elementsRemove: createEventHook<Elements>(),
|
elementsRemove: createEventHook<Elements>(),
|
||||||
@@ -45,33 +57,23 @@ const hooks = (): FlowHooks => {
|
|||||||
edgeUpdateEnd: createEventHook<MouseEvent>(),
|
edgeUpdateEnd: createEventHook<MouseEvent>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const createHooks = (): FlowHooks & { bind: (emit: EmitFunc) => FlowHooks } => {
|
|
||||||
const eventHooks = hooks()
|
|
||||||
const bind = (emit: EmitFunc) => {
|
|
||||||
for (const [key, value] of Object.entries(eventHooks)) {
|
|
||||||
value.on((data: unknown) => {
|
|
||||||
emit(key as keyof FlowHooks, data)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return eventHooks
|
const bind = (emit: EmitFunc, hooks: FlowHooks) => {
|
||||||
}
|
for (const [key, value] of Object.entries(hooks)) {
|
||||||
|
value.on((data: FlowEvents[keyof FlowHooks]) => {
|
||||||
return {
|
emit(key as keyof FlowHooks, data)
|
||||||
...eventHooks,
|
})
|
||||||
bind,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (emit?: EmitFunc) => {
|
export default (emit?: EmitFunc) => {
|
||||||
let hooks = inject(Hooks)!
|
let hooks = inject(Hooks)!
|
||||||
if (!hooks) {
|
if (!hooks) {
|
||||||
|
const store = useStore()
|
||||||
if (import.meta.env.DEV) console.warn('hooks context not found; creating default hooks')
|
if (import.meta.env.DEV) console.warn('hooks context not found; creating default hooks')
|
||||||
if (!emit) console.error('no emit function found for hook context.')
|
hooks = store.hooks
|
||||||
else {
|
if (typeof emit === 'function') bind(emit, hooks)
|
||||||
hooks = createHooks().bind(emit)
|
provide(Hooks, hooks)
|
||||||
provide(Hooks, hooks)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return hooks
|
return hooks
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Store } from '~/context'
|
|||||||
|
|
||||||
export default (options?: Partial<FlowOptions>) => {
|
export default (options?: Partial<FlowOptions>) => {
|
||||||
let store = inject(Store)!
|
let store = inject(Store)!
|
||||||
|
|
||||||
if (!store) {
|
if (!store) {
|
||||||
if (import.meta.env.DEV) console.warn('store context not found; creating default store')
|
if (import.meta.env.DEV) console.warn('store context not found; creating default store')
|
||||||
store = useFlowStore({
|
store = useFlowStore({
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
import useHooks from './useHooks'
|
import useHooks from './useHooks'
|
||||||
import useStore from './useStore'
|
import useStore from './useStore'
|
||||||
import { FlowInstance } from '~/types'
|
import { EmitFunc } from '~/types'
|
||||||
|
|
||||||
export default () => {
|
export const initFlow = (emit: EmitFunc) => {
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const hooks = useHooks()
|
const hooks = useHooks(emit)
|
||||||
const isReady = ref(false)
|
|
||||||
const instance = ref<FlowInstance>()
|
|
||||||
hooks.load.on((flow) => {
|
|
||||||
isReady.value = true
|
|
||||||
instance.value = flow
|
|
||||||
if (import.meta.env.DEV) console.log(`vue flow ${store.$id} ready.`)
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isReady,
|
|
||||||
instance,
|
|
||||||
store,
|
store,
|
||||||
hooks,
|
hooks,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default () => useStore()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CSSProperties, onBeforeUnmount } from 'vue'
|
import { CSSProperties, onBeforeUnmount } from 'vue'
|
||||||
import { invoke } from '@vueuse/core'
|
import { invoke } from '@vueuse/core'
|
||||||
|
import diff from 'microdiff'
|
||||||
import {
|
import {
|
||||||
ConnectionLineType,
|
ConnectionLineType,
|
||||||
ConnectionMode,
|
ConnectionMode,
|
||||||
@@ -12,14 +13,15 @@ import {
|
|||||||
TranslateExtent,
|
TranslateExtent,
|
||||||
NodeExtent,
|
NodeExtent,
|
||||||
FlowOptions,
|
FlowOptions,
|
||||||
|
FlowEvents,
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
import { useHooks, useStore, createHooks } from '../../composables'
|
|
||||||
import ZoomPane from '../../container/ZoomPane/ZoomPane.vue'
|
import ZoomPane from '../../container/ZoomPane/ZoomPane.vue'
|
||||||
import SelectionPane from '../../container/SelectionPane/SelectionPane.vue'
|
import SelectionPane from '../../container/SelectionPane/SelectionPane.vue'
|
||||||
import NodeRenderer from '../../container/NodeRenderer/NodeRenderer.vue'
|
import NodeRenderer from '../../container/NodeRenderer/NodeRenderer.vue'
|
||||||
import EdgeRenderer from '../../container/EdgeRenderer/EdgeRenderer.vue'
|
import EdgeRenderer from '../../container/EdgeRenderer/EdgeRenderer.vue'
|
||||||
import { DefaultNode, InputNode, OutputNode } from '../../components/Nodes'
|
import { DefaultNode, InputNode, OutputNode } from '../../components/Nodes'
|
||||||
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'
|
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '../../components/Edges'
|
||||||
|
import { initFlow } from '~/composables'
|
||||||
|
|
||||||
export interface FlowProps extends FlowOptions {
|
export interface FlowProps extends FlowOptions {
|
||||||
elements: Elements
|
elements: Elements
|
||||||
@@ -98,7 +100,9 @@ const props = withDefaults(defineProps<FlowProps>(), {
|
|||||||
edgeTypesId: '1',
|
edgeTypesId: '1',
|
||||||
nodeTypesId: '1',
|
nodeTypesId: '1',
|
||||||
})
|
})
|
||||||
const emit = defineEmits(Object.keys(createHooks()))
|
export type DefineFlowEvents = { (event: keyof FlowEvents, flowEvent: FlowEvents[keyof FlowEvents]): void }
|
||||||
|
|
||||||
|
const emit = defineEmits<DefineFlowEvents>()
|
||||||
|
|
||||||
const defaultNodeTypes: Record<string, NodeType> = {
|
const defaultNodeTypes: Record<string, NodeType> = {
|
||||||
input: InputNode as NodeType,
|
input: InputNode as NodeType,
|
||||||
@@ -113,8 +117,7 @@ const defaultEdgeTypes: Record<string, EdgeType> = {
|
|||||||
smoothstep: SmoothStepEdge as EdgeType,
|
smoothstep: SmoothStepEdge as EdgeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = useStore(props)
|
const { store, hooks } = initFlow(emit)
|
||||||
const hooks = useHooks(emit)
|
|
||||||
|
|
||||||
const init = (opts: typeof props) => {
|
const init = (opts: typeof props) => {
|
||||||
store.$state = { ...store.$state, ...opts }
|
store.$state = { ...store.$state, ...opts }
|
||||||
@@ -124,12 +127,16 @@ const init = (opts: typeof props) => {
|
|||||||
store.setTranslateExtent(opts.translateExtent)
|
store.setTranslateExtent(opts.translateExtent)
|
||||||
store.setNodeExtent(opts.nodeExtent)
|
store.setNodeExtent(opts.nodeExtent)
|
||||||
}
|
}
|
||||||
|
const elements = useVModel(props, 'elements', emit)
|
||||||
|
|
||||||
onBeforeUnmount(() => store?.$dispose())
|
onBeforeUnmount(() => store?.$dispose())
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props,
|
() => props,
|
||||||
(val) => init(val),
|
(val, oldVal) => {
|
||||||
|
const hasDiff = diff(val, oldVal)
|
||||||
|
if (hasDiff.length > 0) init(val)
|
||||||
|
},
|
||||||
{ flush: 'pre', deep: true },
|
{ flush: 'pre', deep: true },
|
||||||
)
|
)
|
||||||
invoke(async () => {
|
invoke(async () => {
|
||||||
@@ -137,16 +144,27 @@ invoke(async () => {
|
|||||||
init(props)
|
init(props)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
elements,
|
||||||
|
(val, oldVal) => {
|
||||||
|
const hasDiff = diff(val, oldVal)
|
||||||
|
if (hasDiff.length > 0) store.setElements(val)
|
||||||
|
},
|
||||||
|
{ flush: 'pre', deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
const nodeTypes = computed(() => {
|
const nodeTypes = computed(() => {
|
||||||
let types = defaultNodeTypes
|
let types = defaultNodeTypes
|
||||||
if (Array.isArray(props.nodeTypes)) props.nodeTypes.forEach((type) => (types[type] = true))
|
if (Array.isArray(props.nodeTypes)) props.nodeTypes.forEach((type) => (types[type] = true))
|
||||||
else types = { ...types, ...props.nodeTypes }
|
else types = { ...types, ...props.nodeTypes }
|
||||||
|
store.$state.nodeTypes = types
|
||||||
return types
|
return types
|
||||||
})
|
})
|
||||||
const edgeTypes = computed(() => {
|
const edgeTypes = computed(() => {
|
||||||
let types = defaultEdgeTypes
|
let types = defaultEdgeTypes
|
||||||
if (Array.isArray(props.edgeTypes)) props.edgeTypes.forEach((type) => (types[type] = true))
|
if (Array.isArray(props.edgeTypes)) props.edgeTypes.forEach((type) => (types[type] = true))
|
||||||
else types = { ...types, ...props.edgeTypes }
|
else types = { ...types, ...props.edgeTypes }
|
||||||
|
store.$state.edgeTypes = types
|
||||||
return types
|
return types
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
||||||
import { get, invoke } from '@vueuse/core'
|
import { get, invoke } from '@vueuse/core'
|
||||||
import { pointer, select } from 'd3-selection'
|
import { pointer, select } from 'd3-selection'
|
||||||
import { FlowTransform, KeyCode, PanOnScrollMode } from '../../types'
|
import { FlowInstance, FlowTransform, KeyCode, PanOnScrollMode } from '../../types'
|
||||||
import { useHooks, useKeyPress, useStore, useZoomPanHelper } from '../../composables'
|
import { useHooks, useKeyPress, useStore, useZoomPanHelper } from '../../composables'
|
||||||
import { clamp, onLoadGetElements, onLoadProject, onLoadToObject } from '../../utils'
|
import { clamp, onLoadGetElements, onLoadProject, onLoadToObject } from '../../utils'
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ store.dimensions = {
|
|||||||
|
|
||||||
invoke(async () => {
|
invoke(async () => {
|
||||||
await until(() => !isNaN(width.value) && width.value > 0 && !isNaN(height.value) && height.value > 0).toBeTruthy()
|
await until(() => !isNaN(width.value) && width.value > 0 && !isNaN(height.value) && height.value > 0).toBeTruthy()
|
||||||
hooks.load.trigger({
|
const instance: FlowInstance = {
|
||||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||||
zoomIn,
|
zoomIn,
|
||||||
zoomOut,
|
zoomOut,
|
||||||
@@ -195,7 +195,8 @@ invoke(async () => {
|
|||||||
project: onLoadProject(store),
|
project: onLoadProject(store),
|
||||||
getElements: onLoadGetElements(store),
|
getElements: onLoadGetElements(store),
|
||||||
toObject: onLoadToObject(store),
|
toObject: onLoadToObject(store),
|
||||||
})
|
}
|
||||||
|
hooks.load.trigger(instance)
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ import { ElementId, FlowHooks, FlowStore } from '~/types'
|
|||||||
|
|
||||||
export const Store: InjectionKey<FlowStore> = Symbol('store')
|
export const Store: InjectionKey<FlowStore> = Symbol('store')
|
||||||
export const Hooks: InjectionKey<FlowHooks> = Symbol('hooks')
|
export const Hooks: InjectionKey<FlowHooks> = Symbol('hooks')
|
||||||
export const NodeIdContextKey: InjectionKey<ElementId> = Symbol('NodeIdContext')
|
export const NodeId: InjectionKey<ElementId> = Symbol('nodeId')
|
||||||
|
|||||||
+1
-3
@@ -19,11 +19,9 @@ export {
|
|||||||
graphPosToZoomedPos,
|
graphPosToZoomedPos,
|
||||||
} from './utils/graph'
|
} from './utils/graph'
|
||||||
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
export { default as useZoomPanHelper } from './composables/useZoomPanHelper'
|
||||||
export { default as useStore } from './composables/useStore'
|
export { default as useVueFlow } from './composables/useVueFlow'
|
||||||
export { default as useHooks } from './composables/useHooks'
|
|
||||||
export { default as useHandle } from './composables/useHandle'
|
export { default as useHandle } from './composables/useHandle'
|
||||||
export { default as useKeyPress } from './composables/useKeyPress'
|
export { default as useKeyPress } from './composables/useKeyPress'
|
||||||
export { default as useVueFlow } from './composables/useVueFlow'
|
|
||||||
|
|
||||||
export * from './additional-components'
|
export * from './additional-components'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia'
|
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia'
|
||||||
import diff from 'microdiff'
|
import diff from 'microdiff'
|
||||||
import { Edge, FlowState, Node, FlowActions } from '~/types'
|
import { Edge, FlowState, Node, FlowActions, Elements, NodeExtent } from '~/types'
|
||||||
import {
|
import {
|
||||||
clampPosition,
|
clampPosition,
|
||||||
getDimensions,
|
getDimensions,
|
||||||
@@ -21,7 +21,54 @@ type NextElements = {
|
|||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
let id = 0
|
let id = 0
|
||||||
|
|
||||||
export default function useFlowStore(preloadedState: FlowState): StoreDefinition<string, FlowState, any, FlowActions> {
|
const parseElements = (elements: Elements, nodes: Node[], edges: Edge[], nodeExtent: NodeExtent) => {
|
||||||
|
const nextElements: NextElements = {
|
||||||
|
nextNodes: [],
|
||||||
|
nextEdges: [],
|
||||||
|
}
|
||||||
|
for (const element of elements) {
|
||||||
|
if (isNode(element)) {
|
||||||
|
const storeNode = nodes.find((node) => node.id === element.id)
|
||||||
|
|
||||||
|
if (storeNode) {
|
||||||
|
const updatedNode: Node = {
|
||||||
|
...storeNode,
|
||||||
|
...element,
|
||||||
|
}
|
||||||
|
if (!updatedNode.__rf) updatedNode.__rf = {}
|
||||||
|
|
||||||
|
if (storeNode.position.x !== element.position.x || storeNode.position.y !== element.position.y) {
|
||||||
|
updatedNode.__rf.position = element.position
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof element.type !== 'undefined' && element.type !== storeNode.type) {
|
||||||
|
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
||||||
|
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
||||||
|
updatedNode.__rf.width = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
nextElements.nextNodes.push(updatedNode)
|
||||||
|
} else {
|
||||||
|
nextElements.nextNodes.push(parseNode(element, nodeExtent))
|
||||||
|
}
|
||||||
|
} else if (isEdge(element)) {
|
||||||
|
const storeEdge = edges.find((se) => se.id === element.id)
|
||||||
|
|
||||||
|
if (storeEdge) {
|
||||||
|
nextElements.nextEdges.push({
|
||||||
|
...storeEdge,
|
||||||
|
...element,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
nextElements.nextEdges.push(parseEdge(element))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextElements
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function flowStore(preloadedState: FlowState): StoreDefinition<string, FlowState, any, FlowActions> {
|
||||||
setActivePinia(pinia)
|
setActivePinia(pinia)
|
||||||
|
|
||||||
return defineStore({
|
return defineStore({
|
||||||
@@ -32,51 +79,7 @@ export default function useFlowStore(preloadedState: FlowState): StoreDefinition
|
|||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
setElements(elements) {
|
setElements(elements) {
|
||||||
const nextElements: NextElements = {
|
const { nextNodes, nextEdges } = parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
||||||
nextNodes: [],
|
|
||||||
nextEdges: [],
|
|
||||||
}
|
|
||||||
const { nextNodes, nextEdges } = elements.reduce((res, propElement): NextElements => {
|
|
||||||
if (isNode(propElement)) {
|
|
||||||
const storeNode = this.nodes.find((node) => node.id === propElement.id)
|
|
||||||
|
|
||||||
if (storeNode) {
|
|
||||||
const updatedNode: Node = {
|
|
||||||
...storeNode,
|
|
||||||
...propElement,
|
|
||||||
}
|
|
||||||
if (!updatedNode.__rf) updatedNode.__rf = {}
|
|
||||||
|
|
||||||
if (storeNode.position.x !== propElement.position.x || storeNode.position.y !== propElement.position.y) {
|
|
||||||
updatedNode.__rf.position = propElement.position
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof propElement.type !== 'undefined' && propElement.type !== storeNode.type) {
|
|
||||||
// we reset the elements dimensions here in order to force a re-calculation of the bounds.
|
|
||||||
// When the type of a node changes it is possible that the number or positions of handles changes too.
|
|
||||||
updatedNode.__rf.width = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
res.nextNodes.push(updatedNode)
|
|
||||||
} else {
|
|
||||||
res.nextNodes.push(parseNode(propElement, this.nodeExtent))
|
|
||||||
}
|
|
||||||
} else if (isEdge(propElement)) {
|
|
||||||
const storeEdge = this.edges.find((se) => se.id === propElement.id)
|
|
||||||
|
|
||||||
if (storeEdge) {
|
|
||||||
res.nextEdges.push({
|
|
||||||
...storeEdge,
|
|
||||||
...propElement,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
res.nextEdges.push(parseEdge(propElement))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}, nextElements)
|
|
||||||
|
|
||||||
this.nodes = nextNodes
|
this.nodes = nextNodes
|
||||||
this.edges = nextEdges
|
this.edges = nextEdges
|
||||||
},
|
},
|
||||||
@@ -257,6 +260,11 @@ export default function useFlowStore(preloadedState: FlowState): StoreDefinition
|
|||||||
this.nodesConnectable = isInteractive
|
this.nodesConnectable = isInteractive
|
||||||
this.elementsSelectable = isInteractive
|
this.elementsSelectable = isInteractive
|
||||||
},
|
},
|
||||||
|
addElements(elements: Elements) {
|
||||||
|
const { nextNodes, nextEdges } = parseElements(elements, this.nodes, this.edges, this.nodeExtent)
|
||||||
|
this.nodes = [...this.nodes, ...nextNodes]
|
||||||
|
this.edges = [...this.edges, ...nextEdges]
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+7
-1
@@ -1,4 +1,5 @@
|
|||||||
import { ConnectionMode, FlowState } from '~/types'
|
import { ConnectionMode, FlowState } from '~/types'
|
||||||
|
import { createHooks } from '~/composables'
|
||||||
|
|
||||||
export const initialState = (): FlowState => ({
|
export const initialState = (): FlowState => ({
|
||||||
dimensions: {
|
dimensions: {
|
||||||
@@ -6,6 +7,8 @@ export const initialState = (): FlowState => ({
|
|||||||
height: 0,
|
height: 0,
|
||||||
},
|
},
|
||||||
transform: [0, 0, 1],
|
transform: [0, 0, 1],
|
||||||
|
nodeTypes: [],
|
||||||
|
edgeTypes: [],
|
||||||
elements: [],
|
elements: [],
|
||||||
nodes: [],
|
nodes: [],
|
||||||
edges: [],
|
edges: [],
|
||||||
@@ -54,7 +57,10 @@ export const initialState = (): FlowState => ({
|
|||||||
|
|
||||||
multiSelectionActive: false,
|
multiSelectionActive: false,
|
||||||
|
|
||||||
|
isReady: false,
|
||||||
|
hooks: createHooks(),
|
||||||
|
|
||||||
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
|
||||||
})
|
})
|
||||||
|
|
||||||
export { default as useFlowStore } from './useFlowStore'
|
export { default as useFlowStore } from './flowStore'
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ export interface FlowActions {
|
|||||||
updateSize: (size: Dimensions) => void
|
updateSize: (size: Dimensions) => void
|
||||||
setConnectionNodeId: (payload: SetConnectionId) => void
|
setConnectionNodeId: (payload: SetConnectionId) => void
|
||||||
setInteractive: (isInteractive: boolean) => void
|
setInteractive: (isInteractive: boolean) => void
|
||||||
|
addElements: (elements: Elements) => void
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -2,17 +2,20 @@ import { Store } from 'pinia'
|
|||||||
import { Dimensions, ElementId, Elements, Rect, SelectionRect, SnapGrid, Transform, XYPosition } from './types'
|
import { Dimensions, ElementId, Elements, Rect, SelectionRect, SnapGrid, Transform, XYPosition } from './types'
|
||||||
import { HandleType } from './handle'
|
import { HandleType } from './handle'
|
||||||
import { ConnectionMode, OnConnectEndFunc, OnConnectFunc, OnConnectStartFunc, OnConnectStopFunc } from './connection'
|
import { ConnectionMode, OnConnectEndFunc, OnConnectFunc, OnConnectStartFunc, OnConnectStopFunc } from './connection'
|
||||||
import { Edge } from './edge'
|
import { Edge, EdgeType } from './edge'
|
||||||
import { Node, NodeExtent, TranslateExtent } from './node'
|
import { Node, NodeExtent, NodeType, TranslateExtent } from './node'
|
||||||
import { FlowActions } from './actions'
|
import { FlowActions } from './actions'
|
||||||
import { D3Selection, D3Zoom, D3ZoomHandler } from './panel'
|
import { D3Selection, D3Zoom, D3ZoomHandler } from './panel'
|
||||||
|
import { FlowHooks } from '~/types/hooks'
|
||||||
|
|
||||||
export interface FlowState {
|
export interface FlowState {
|
||||||
dimensions: Dimensions
|
dimensions: Dimensions
|
||||||
transform: Transform
|
transform: Transform
|
||||||
elements: Elements
|
elements: Elements
|
||||||
nodes: Node[]
|
nodes: Node[]
|
||||||
|
nodeTypes: Record<string, NodeType> | string[]
|
||||||
edges: Edge[]
|
edges: Edge[]
|
||||||
|
edgeTypes: Record<string, EdgeType> | string[]
|
||||||
selectedElements?: Elements
|
selectedElements?: Elements
|
||||||
selectedNodesBbox: Rect
|
selectedNodesBbox: Rect
|
||||||
|
|
||||||
@@ -50,6 +53,9 @@ export interface FlowState {
|
|||||||
onConnectStart?: OnConnectStartFunc
|
onConnectStart?: OnConnectStartFunc
|
||||||
onConnectStop?: OnConnectStopFunc
|
onConnectStop?: OnConnectStopFunc
|
||||||
onConnectEnd?: OnConnectEndFunc
|
onConnectEnd?: OnConnectEndFunc
|
||||||
|
|
||||||
|
isReady: boolean
|
||||||
|
hooks: FlowHooks
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FlowStore = Store<string, FlowState, any, FlowActions>
|
export type FlowStore = Store<string, FlowState, any, FlowActions>
|
||||||
|
|||||||
Reference in New Issue
Block a user