refactor(flow): Watch models
* replace model value after re-setting elements/nodes/edges Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { createHooks, useHooks } from '../../store'
|
||||
import type { FlowProps } from '../../types/flow'
|
||||
import ZoomPane from '../ZoomPane/ZoomPane.vue'
|
||||
import { createHooks, useHooks } from '../../store'
|
||||
import { useVueFlow, applyNodeChanges, applyEdgeChanges } from '../../composables'
|
||||
import type { FlowProps } from '../../types/flow'
|
||||
import useWatch from './watch'
|
||||
|
||||
const props = withDefaults(defineProps<FlowProps>(), {
|
||||
@@ -21,23 +21,39 @@ const props = withDefaults(defineProps<FlowProps>(), {
|
||||
paneMoveable: true,
|
||||
applyDefault: true,
|
||||
})
|
||||
const emit = defineEmits([...Object.keys(createHooks()), 'update:modelValue', 'update:edges', 'update:nodes'])
|
||||
const emit = defineEmits([...Object.keys(createHooks()), 'update:modelValue', 'update:elements', 'update:edges', 'update:nodes'])
|
||||
|
||||
const {
|
||||
id,
|
||||
store,
|
||||
hooks,
|
||||
applyDefault,
|
||||
setElements,
|
||||
setEdges,
|
||||
setNodes,
|
||||
getNodeTypes,
|
||||
getEdgeTypes,
|
||||
onNodesChange,
|
||||
onEdgesChange,
|
||||
nodes: storedNodes,
|
||||
edges: storedEdges,
|
||||
} = useVueFlow(props)
|
||||
useHooks(hooks.value, emit)
|
||||
const { modelValue, nodes, edges } = useVModels(props, emit)
|
||||
|
||||
const { id, store } = useVueFlow(props)
|
||||
useHooks(store.hooks, emit)
|
||||
|
||||
if (store.applyDefault) {
|
||||
store.hooks.nodesChange.on((c) => applyNodeChanges(c, store.nodes))
|
||||
store.hooks.edgesChange.on((c) => applyEdgeChanges(c, store.edges))
|
||||
if (applyDefault.value) {
|
||||
onNodesChange((c) => applyNodeChanges(c, storedNodes.value))
|
||||
onEdgesChange((c) => applyEdgeChanges(c, storedEdges.value))
|
||||
}
|
||||
if (modelValue?.value && !store.nodes.length) store.setElements(modelValue.value)
|
||||
if (nodes?.value && !store.nodes.length) store.setNodes(nodes.value)
|
||||
if (edges?.value && !store.edges.length) store.setEdges(edges.value)
|
||||
onMounted(() => useWatch(modelValue, nodes, edges, props, store))
|
||||
modelValue && (modelValue.value = [...store.nodes, ...store.edges])
|
||||
nodes && (nodes.value = store.nodes)
|
||||
edges && (edges.value = store.edges)
|
||||
if (props.modelValue && !storedNodes.value.length) setElements(props.modelValue)
|
||||
if (props.nodes && !storedNodes.value.length) setNodes(props.nodes)
|
||||
if (props.edges && !storedEdges.value.length) setEdges(props.edges)
|
||||
|
||||
if (modelValue.value) modelValue.value = [...store.nodes, ...store.edges]
|
||||
if (nodes && nodes.value) nodes.value = store.nodes
|
||||
if (edges && edges.value) edges.value = store.edges
|
||||
|
||||
onMounted(() => useWatch({ modelValue, nodes, edges }, props, store))
|
||||
</script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
@@ -47,18 +63,10 @@ export default {
|
||||
<template>
|
||||
<div class="vue-flow">
|
||||
<ZoomPane :key="`renderer-${id}`">
|
||||
<template
|
||||
v-for="nodeName of Object.keys(store.getNodeTypes)"
|
||||
#[`node-${nodeName}`]="nodeProps"
|
||||
:key="`node-${nodeName}-${id}`"
|
||||
>
|
||||
<template v-for="nodeName of Object.keys(getNodeTypes)" #[`node-${nodeName}`]="nodeProps" :key="`node-${nodeName}-${id}`">
|
||||
<slot :name="`node-${nodeName}`" v-bind="nodeProps" />
|
||||
</template>
|
||||
<template
|
||||
v-for="edgeName of Object.keys(store.getEdgeTypes)"
|
||||
#[`edge-${edgeName}`]="edgeProps"
|
||||
:key="`edge-${edgeName}-${id}`"
|
||||
>
|
||||
<template v-for="edgeName of Object.keys(getEdgeTypes)" #[`edge-${edgeName}`]="edgeProps" :key="`edge-${edgeName}-${id}`">
|
||||
<slot :name="`edge-${edgeName}`" v-bind="edgeProps" />
|
||||
</template>
|
||||
<template #connection-line="customConnectionLineProps">
|
||||
|
||||
@@ -1,37 +1,49 @@
|
||||
import { Ref } from 'vue'
|
||||
import { FlowProps, FlowStore } from '~/types'
|
||||
import { FlowProps, FlowStore, Node, Edge, Elements } from '~/types'
|
||||
|
||||
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
|
||||
export default (
|
||||
modelValue: Ref<any[] | undefined> | undefined,
|
||||
nodes: Ref<any[] | undefined> | undefined,
|
||||
edges: Ref<any[] | undefined> | undefined,
|
||||
{
|
||||
modelValue,
|
||||
nodes,
|
||||
edges,
|
||||
}: {
|
||||
modelValue?: Ref<Elements>
|
||||
nodes?: Ref<Node[] | undefined>
|
||||
edges?: Ref<Edge[] | undefined>
|
||||
},
|
||||
props: FlowProps,
|
||||
store: FlowStore,
|
||||
) => {
|
||||
if (isDefined(modelValue)) {
|
||||
const { pause, resume } = pausableWatch(modelValue, (v) => {
|
||||
if (v) {
|
||||
if (isDefined(props.modelValue)) {
|
||||
const { pause, resume } = pausableWatch([() => props.modelValue, () => props.modelValue.length], async ([v]) => {
|
||||
if (v && Array.isArray(v)) {
|
||||
pause()
|
||||
store.setElements(v)
|
||||
if (modelValue) modelValue.value = [...store.nodes, ...store.edges]
|
||||
await nextTick()
|
||||
resume()
|
||||
}
|
||||
})
|
||||
}
|
||||
if (isDefined(nodes)) {
|
||||
const { pause, resume } = pausableWatch(nodes, (v) => {
|
||||
if (v) {
|
||||
if (isDefined(props.nodes)) {
|
||||
const { pause, resume } = pausableWatch([() => props.nodes, () => props.nodes?.length], async ([v]) => {
|
||||
if (v && Array.isArray(v)) {
|
||||
pause()
|
||||
store.setNodes(v)
|
||||
if (nodes) nodes.value = store.nodes
|
||||
await nextTick()
|
||||
resume()
|
||||
}
|
||||
})
|
||||
}
|
||||
if (isDefined(edges)) {
|
||||
const { pause, resume } = pausableWatch(edges, (v) => {
|
||||
if (v) {
|
||||
if (isDefined(props.edges)) {
|
||||
const { pause, resume } = pausableWatch([() => props.edges, () => props.edges?.length], async ([v]) => {
|
||||
if (v && Array.isArray(v)) {
|
||||
pause()
|
||||
store.setEdges(v)
|
||||
if (edges) edges.value = store.edges
|
||||
await nextTick()
|
||||
resume()
|
||||
}
|
||||
})
|
||||
@@ -192,4 +204,9 @@ export default (
|
||||
(v) => isDef(v) && (store.applyDefault = v),
|
||||
{ immediate: true },
|
||||
)
|
||||
watch(
|
||||
() => props.fitViewOnInit,
|
||||
(v) => isDef(v) && (store.fitViewOnInit = v),
|
||||
{ immediate: true },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ export default (state: State, getters: Getters): Actions => {
|
||||
}
|
||||
|
||||
const setNodes: Actions['setNodes'] = (nodes, extent?: CoordinateExtent) => {
|
||||
if (!state.initialized && !nodes.length) return
|
||||
nodes = nodes.flatMap((node) => {
|
||||
const children: GraphNode[] = []
|
||||
parseChildren(node, undefined, children, extent ?? state.nodeExtent, getters.getNode.value)
|
||||
@@ -120,6 +121,7 @@ export default (state: State, getters: Getters): Actions => {
|
||||
state.nodes = <GraphNode[]>nodes
|
||||
}
|
||||
const setEdges: Actions['setEdges'] = (edges) => {
|
||||
if (!state.initialized && !edges.length) return
|
||||
state.edges = edges.map((edge) => {
|
||||
const sourceNode = getters.getNode.value(edge.source)!
|
||||
const targetNode = getters.getNode.value(edge.target)!
|
||||
@@ -128,11 +130,13 @@ export default (state: State, getters: Getters): Actions => {
|
||||
if (!targetNode || typeof targetNode === 'undefined')
|
||||
console.warn(`couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
|
||||
|
||||
return parseEdge(edge, {
|
||||
...getters.getEdge.value(edge.id),
|
||||
return {
|
||||
...parseEdge(edge, {
|
||||
...getters.getEdge.value(edge.id),
|
||||
}),
|
||||
sourceNode,
|
||||
targetNode,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ export type FlowInstance<N = any, E = N> = {
|
||||
} & UseZoomPanHelper
|
||||
|
||||
export interface FlowProps<N = any, E = N> {
|
||||
modelValue?: any[]
|
||||
modelValue: Elements
|
||||
nodes?: Node<N>[]
|
||||
edges?: Edge<E>[]
|
||||
id?: string
|
||||
|
||||
Reference in New Issue
Block a user