feat(types): Add NodeTypes and EdgeTypes

* Interface for passing an object of NodeTypes/EdgeTypes
* Object needs to be passed with components markedRaw

Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
Braks
2021-11-19 17:47:57 +01:00
parent 8c4747a8a9
commit 37388ddf47
17 changed files with 69 additions and 74 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ const bgColor = ref('#1A192B')
const connectionLineStyle = { stroke: '#fff' } const connectionLineStyle = { stroke: '#fff' }
const snapGrid: SnapGrid = [16, 16] const snapGrid: SnapGrid = [16, 16]
const nodeTypes = { const nodeTypes = {
selectorNode: ColorSelectorNode, selectorNode: markRaw(ColorSelectorNode),
} }
const onLoad = (flowInstance: FlowInstance) => { const onLoad = (flowInstance: FlowInstance) => {
@@ -2,7 +2,7 @@
import { CSSProperties } from 'vue' import { CSSProperties } from 'vue'
import NodeA from './NodeA.vue' import NodeA from './NodeA.vue'
import NodeB from './NodeB.vue' import NodeB from './NodeB.vue'
import { VueFlow, Elements, Position, NodeType, Connection, Edge, addEdge } from '~/index' import { VueFlow, Elements, Position, Connection, Edge, addEdge, NodeTypes } from '~/index'
const initialElements: Elements = [ const initialElements: Elements = [
{ {
@@ -25,16 +25,13 @@ const initialElements: Elements = [
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 } const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 }
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' } const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' }
type NodeTypesObject = {
[key: string]: Record<string, NodeType>
}
const nodeTypesObjects: NodeTypesObject = { const nodeTypesObjects: Record<string, NodeTypes> = {
a: { a: {
a: NodeA as NodeType, a: NodeA,
}, },
b: { b: {
b: NodeB as NodeType, b: NodeB,
}, },
} }
@@ -14,6 +14,7 @@ import {
ConnectionMode, ConnectionMode,
updateEdge, updateEdge,
ArrowHeadType, ArrowHeadType,
NodeTypes,
} from '~/index' } from '~/index'
const initialElements: Elements = [ const initialElements: Elements = [
@@ -172,8 +173,8 @@ const initialElements: Elements = [
}, },
] ]
const nodeTypes: Record<string, NodeType> = { const nodeTypes: NodeTypes = {
custom: CustomNode as NodeType, custom: CustomNode,
} }
let id = 4 let id = 4
@@ -14,6 +14,7 @@ import {
Position, Position,
isEdge, isEdge,
FlowInstance, FlowInstance,
NodeTypes,
} from '~/index' } from '~/index'
const initialHandleCount = 1 const initialHandleCount = 1
@@ -29,8 +30,8 @@ const initialElements: Elements = [
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 10 } const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 10 }
const nodeTypes: Record<string, NodeType> = { const nodeTypes: NodeTypes = {
custom: CustomNode as NodeType, custom: CustomNode,
} }
let id = 5 let id = 5
+4 -3
View File
@@ -13,6 +13,7 @@ import {
NodeProps, NodeProps,
FlowInstance, FlowInstance,
NodeType, NodeType,
NodeTypes,
} from '~/index' } from '~/index'
import './validation.css' import './validation.css'
@@ -34,9 +35,9 @@ const onConnect = (params: Connection | Edge) => {
console.log('on connect', params) console.log('on connect', params)
elements.value = addEdge(params, elements.value) elements.value = addEdge(params, elements.value)
} }
const nodeTypes: Record<string, NodeType> = { const nodeTypes: NodeTypes = {
custominput: CustomInput as NodeType, custominput: CustomInput,
customnode: CustomNode as NodeType, customnode: CustomNode,
} }
</script> </script>
<template> <template>
+9 -3
View File
@@ -1,12 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useHandle, useStore } from '../../composables' import { useHandle, useStore } from '../../composables'
import { ConnectionMode, Edge, EdgePositions, EdgeType, Position } from '../../types' import { ConnectionMode, Edge, EdgePositions, Position } from '../../types'
import EdgeAnchor from './EdgeAnchor.vue' import EdgeAnchor from './EdgeAnchor.vue'
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils' import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '~/container/EdgeRenderer/utils'
import { isEdge } from '~/utils' import { isEdge } from '~/utils'
interface EdgeProps { interface EdgeProps {
type: EdgeType
edge: Edge edge: Edge
markerEndId?: string markerEndId?: string
edgeUpdaterRadius?: number edgeUpdaterRadius?: number
@@ -16,6 +15,12 @@ const props = withDefaults(defineProps<EdgeProps>(), {})
const store = useStore() const store = useStore()
const edgeType = props.edge.type || 'default'
const type = store.getEdgeTypes[edgeType] || store.getEdgeTypes.default
if (!store.getEdgeTypes[edgeType]) {
console.warn(`Edge type "${edgeType}" not found. Using fallback type "default".`)
}
const onEdgeClick = (event: MouseEvent) => { const onEdgeClick = (event: MouseEvent) => {
if (store.elementsSelectable) { if (store.elementsSelectable) {
store.unsetNodesSelection() store.unsetNodesSelection()
@@ -166,7 +171,8 @@ const elementsSelectable = computed(() => store.elementsSelectable)
}" }"
> >
<component <component
:is="props.type" :is="type"
v-if="typeof type !== 'boolean'"
v-bind="{ v-bind="{
id: props.edge.id, id: props.edge.id,
source: props.edge.source, source: props.edge.source,
+1 -1
View File
@@ -19,7 +19,7 @@ const props = withDefaults(defineProps<HandleProps>(), {
}) })
const store = useStore() const store = useStore()
const nodeId = inject(NodeId)! const nodeId = inject(NodeId, '')!
const handler = useHandle() const handler = useHandle()
const onMouseDownHandler = (event: MouseEvent) => const onMouseDownHandler = (event: MouseEvent) =>
+9 -3
View File
@@ -1,12 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable' import { DraggableEventListener, DraggableCore } from '@braks/revue-draggable'
import { useStore } from '../../composables' import { useStore } from '../../composables'
import { Node, NodeType, SnapGrid } from '../../types' import { Node, SnapGrid } from '../../types'
import { NodeId } from '../../context' import { NodeId } from '../../context'
interface NodeProps { interface NodeProps {
node: Node node: Node
type: NodeType
selectNodesOnDrag?: boolean selectNodesOnDrag?: boolean
snapGrid?: SnapGrid snapGrid?: SnapGrid
} }
@@ -21,6 +20,12 @@ provide(NodeId, props.node.id)
const nodeElement = templateRef<HTMLDivElement>('node-element', null) const nodeElement = templateRef<HTMLDivElement>('node-element', null)
const nodeType = props.node.type || 'default'
const type = store.getNodeTypes[nodeType] || store.getNodeTypes.default
if (!store.getNodeTypes[nodeType]) {
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`)
}
const selectable = computed(() => const selectable = computed(() =>
typeof props.node.selectable === 'undefined' ? store.elementsSelectable : props.node.selectable, typeof props.node.selectable === 'undefined' ? store.elementsSelectable : props.node.selectable,
) )
@@ -184,7 +189,8 @@ onMounted(() => {
}" }"
> >
<component <component
:is="props.type" :is="type"
v-if="typeof type !== 'boolean'"
v-bind="{ v-bind="{
id: props.node.id, id: props.node.id,
data: props.node.data, data: props.node.data,
@@ -28,14 +28,6 @@ const connectionLineVisible = computed(
) )
const dimensions = computed(() => store.dimensions) const dimensions = computed(() => store.dimensions)
const transform = computed(() => `translate(${store.transform[0]},${store.transform[1]}) scale(${store.transform[2]})`) const transform = computed(() => `translate(${store.transform[0]},${store.transform[1]}) scale(${store.transform[2]})`)
const type = (edge: TEdge) => {
const edgeType = edge.type || 'default'
const type = store.getEdgeTypes[edgeType] || store.getEdgeTypes.default
if (!store.getEdgeTypes[edgeType]) {
console.warn(`Edge type "${edgeType}" not found. Using fallback type "default".`)
}
return type
}
</script> </script>
<template> <template>
<svg :width="dimensions.width" :height="dimensions.height" class="vue-flow__edges"> <svg :width="dimensions.width" :height="dimensions.height" class="vue-flow__edges">
@@ -45,7 +37,6 @@ const type = (edge: TEdge) => {
v-for="edge of store.getEdges" v-for="edge of store.getEdges"
:key="edge.id" :key="edge.id"
:edge="edge" :edge="edge"
:type="type(edge)"
:marker-end-id="props.markerEndId" :marker-end-id="props.markerEndId"
:edge-updater-radius="props.edgeUpdaterRadius" :edge-updater-radius="props.edgeUpdaterRadius"
> >
@@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { invoke } from '@vueuse/core' import { invoke } from '@vueuse/core'
import { Node as TNode } from '../../types'
import { useStore } from '../../composables' import { useStore } from '../../composables'
import Node from '../../components/Nodes/Node.vue' import Node from '../../components/Nodes/Node.vue'
@@ -17,14 +16,6 @@ const store = useStore()
const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`) const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`)
const snapGrid = computed(() => (store.snapToGrid ? store.snapGrid : undefined)) const snapGrid = computed(() => (store.snapToGrid ? store.snapGrid : undefined))
const type = (node: TNode) => {
const nodeType = node.type || 'default'
const type = store.getNodeTypes[nodeType] || store.getNodeTypes.default
if (!store.getNodeTypes[nodeType]) {
console.warn(`Node type "${nodeType}" not found. Using fallback type "default".`)
}
return type
}
invoke(async () => { invoke(async () => {
await until(store.getNodes).toMatch((y) => y.length > 0) await until(store.getNodes).toMatch((y) => y.length > 0)
await until(store.transform).toMatch(([x, y, z]) => x !== 0 && y !== 0 && z !== 1) await until(store.transform).toMatch(([x, y, z]) => x !== 0 && y !== 0 && z !== 1)
@@ -37,7 +28,6 @@ invoke(async () => {
v-for="node of store.getNodes" v-for="node of store.getNodes"
:key="node.id" :key="node.id"
:node="node" :node="node"
:type="type(node)"
:snap-grid="snapGrid" :snap-grid="snapGrid"
:select-nodes-on-drag="props.selectNodesOnDrag" :select-nodes-on-drag="props.selectNodesOnDrag"
> >
+4 -4
View File
@@ -6,12 +6,12 @@ import {
ConnectionMode, ConnectionMode,
Elements, Elements,
PanOnScrollMode, PanOnScrollMode,
NodeType,
EdgeType,
KeyCode, KeyCode,
TranslateExtent, TranslateExtent,
NodeExtent, NodeExtent,
FlowOptions, FlowOptions,
NodeTypes,
EdgeTypes,
} from '../../types' } from '../../types'
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'
@@ -22,8 +22,8 @@ import { createHooks, initFlow } from '../../composables'
export interface FlowProps extends Partial<FlowOptions> { export interface FlowProps extends Partial<FlowOptions> {
modelValue?: Elements modelValue?: Elements
elements?: Elements elements?: Elements
nodeTypes?: Record<string, NodeType> nodeTypes?: NodeTypes
edgeTypes?: Record<string, EdgeType> edgeTypes?: EdgeTypes
connectionMode?: ConnectionMode connectionMode?: ConnectionMode
connectionLineType?: ConnectionLineType connectionLineType?: ConnectionLineType
connectionLineStyle?: CSSProperties connectionLineStyle?: CSSProperties
+3 -3
View File
@@ -1,7 +1,7 @@
import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia' import { setActivePinia, createPinia, defineStore, StoreDefinition } from 'pinia'
import diff from 'microdiff' import diff from 'microdiff'
import { parseElements } from './utils' import { parseElements } from './utils'
import { FlowState, Node, FlowActions, Elements, NodeType, EdgeType, FlowGetters, Edge } from '~/types' import { FlowState, Node, FlowActions, Elements, FlowGetters, Edge, EdgeTypes, NodeTypes } from '~/types'
import { clampPosition, getDimensions, getConnectedEdges, getNodesInside, getRectOfNodes, isNode } from '~/utils' import { clampPosition, getDimensions, getConnectedEdges, getNodesInside, getRectOfNodes, isNode } from '~/utils'
import { getHandleBounds } from '~/components/Nodes/utils' import { getHandleBounds } from '~/components/Nodes/utils'
import { defaultEdgeTypes, defaultNodeTypes } from '~/store/index' import { defaultEdgeTypes, defaultNodeTypes } from '~/store/index'
@@ -23,10 +23,10 @@ export default function flowStore(
...preloadedState, ...preloadedState,
}), }),
getters: { getters: {
getEdgeTypes(): Record<string, EdgeType> { getEdgeTypes(): EdgeTypes {
return { ...defaultEdgeTypes, ...this.edgeTypes } return { ...defaultEdgeTypes, ...this.edgeTypes }
}, },
getNodeTypes(): Record<string, NodeType> { getNodeTypes(): NodeTypes {
return { ...defaultNodeTypes, ...this.nodeTypes } return { ...defaultNodeTypes, ...this.nodeTypes }
}, },
getNodes(): Node[] { getNodes(): Node[] {
+10 -10
View File
@@ -1,19 +1,19 @@
import { ConnectionMode, EdgeType, FlowState, NodeType } from '~/types' import { ConnectionMode, EdgeTypes, FlowState, NodeTypes } from '~/types'
import { createHooks } from '~/composables' import { createHooks } from '~/composables'
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'
export const defaultNodeTypes: Record<string, NodeType> = { export const defaultNodeTypes: NodeTypes = {
input: InputNode as NodeType, input: markRaw(InputNode),
default: DefaultNode as NodeType, default: markRaw(DefaultNode),
output: OutputNode as NodeType, output: markRaw(OutputNode),
} }
export const defaultEdgeTypes: Record<string, EdgeType> = { export const defaultEdgeTypes: EdgeTypes = {
default: BezierEdge as EdgeType, default: markRaw(BezierEdge),
straight: StraightEdge as EdgeType, straight: markRaw(StraightEdge),
step: StepEdge as EdgeType, step: markRaw(StepEdge),
smoothstep: SmoothStepEdge as EdgeType, smoothstep: markRaw(SmoothStepEdge),
} }
export const initialState = (): FlowState => ({ export const initialState = (): FlowState => ({
+3 -2
View File
@@ -1,4 +1,4 @@
import { CSSProperties, DefineComponent } from 'vue' import { Component, CSSProperties, DefineComponent } from 'vue'
import { ArrowHeadType, ElementId, Position } from './types' import { ArrowHeadType, ElementId, Position } from './types'
export interface Edge<T = any> { export interface Edge<T = any> {
@@ -48,7 +48,8 @@ export interface EdgeSmoothStepProps<T = any> extends EdgeProps<T> {
borderRadius?: number borderRadius?: number
} }
export type EdgeType = DefineComponent<EdgeSmoothStepProps, any, any, any, any, any> | boolean export type EdgeType = Component<EdgeProps> | DefineComponent<EdgeSmoothStepProps, any, any, any, any, any> | boolean
export type EdgeTypes = Record<string, EdgeType>
export interface EdgePositions { export interface EdgePositions {
sourceX: number sourceX: number
+3 -2
View File
@@ -1,4 +1,4 @@
import { DefineComponent } from 'vue' import { Component, DefineComponent } from 'vue'
import { XYPosition, ElementId, Position } from './types' import { XYPosition, ElementId, Position } from './types'
export interface Node<T = any> { export interface Node<T = any> {
@@ -58,4 +58,5 @@ export interface NodeProps<T = any> {
dragging?: boolean dragging?: boolean
} }
export type NodeType = DefineComponent<NodeProps, any, any, any, any> | boolean export type NodeType = Component<NodeProps> | DefineComponent<NodeProps, any, any, any, any> | boolean
export type NodeTypes = Record<string, NodeType>
+6 -6
View File
@@ -13,8 +13,8 @@ import {
} from './types' } 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, EdgeType } from './edge' import { Edge, EdgeTypes } from './edge'
import { Node, NodeExtent, NodeType, TranslateExtent } from './node' import { Node, NodeExtent, NodeTypes, 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 './hooks' import { FlowHooks } from './hooks'
@@ -24,9 +24,9 @@ export interface FlowState extends FlowOptions {
transform: Transform transform: Transform
elements: Elements elements: Elements
nodes: Node[] nodes: Node[]
nodeTypes: Record<string, NodeType> nodeTypes: NodeTypes
edges: Edge[] edges: Edge[]
edgeTypes: Record<string, EdgeType> edgeTypes: EdgeTypes
selectedElements?: Elements selectedElements?: Elements
selectedNodesBbox: Rect selectedNodesBbox: Rect
@@ -72,8 +72,8 @@ export interface FlowState extends FlowOptions {
} }
export interface FlowGetters { export interface FlowGetters {
getEdgeTypes: () => Record<string, EdgeType> getEdgeTypes: () => EdgeTypes
getNodeTypes: () => Record<string, NodeType> getNodeTypes: () => NodeTypes
getNodes: () => Node[] getNodes: () => Node[]
getEdges: () => Edge[] getEdges: () => Edge[]
} }
+6 -6
View File
@@ -1,6 +1,6 @@
import { CSSProperties, HTMLAttributes } from 'vue' import { CSSProperties } from 'vue'
import { Edge, EdgeType } from './edge' import { Edge, EdgeTypes } from './edge'
import { Node, NodeExtent, NodeType, TranslateExtent } from './node' import { Node, NodeExtent, NodeTypes, TranslateExtent } from './node'
import { ConnectionLineType, ConnectionMode } from './connection' import { ConnectionLineType, ConnectionMode } from './connection'
import { KeyCode, PanOnScrollMode } from './panel' import { KeyCode, PanOnScrollMode } from './panel'
@@ -88,10 +88,10 @@ export type FlowInstance<T = any> = {
toObject: ToObjectFunc<T> toObject: ToObjectFunc<T>
} }
export interface FlowOptions extends Omit<HTMLAttributes, 'onLoad'> { export interface FlowOptions {
elements: Elements elements: Elements
nodeTypes?: Record<string, NodeType> nodeTypes?: NodeTypes
edgeTypes?: Record<string, EdgeType> edgeTypes?: EdgeTypes
connectionMode?: ConnectionMode connectionMode?: ConnectionMode
connectionLineType?: ConnectionLineType connectionLineType?: ConnectionLineType
connectionLineStyle?: CSSProperties connectionLineStyle?: CSSProperties