refactor(core): rename core pkg dir to core

This commit is contained in:
braks
2022-10-10 21:33:44 +02:00
committed by Braks
parent f7dd7f1803
commit 082050b164
87 changed files with 640 additions and 0 deletions
+519
View File
@@ -0,0 +1,519 @@
import useState from './state'
import type {
Actions,
ComputedGetters,
CoordinateExtent,
EdgeChange,
EdgeRemoveChange,
FlowExportObject,
GraphEdge,
GraphNode,
NodeChange,
NodeDimensionChange,
NodePositionChange,
NodeRemoveChange,
State,
} from '~/types'
import {
addEdgeToStore,
applyChanges,
createAdditionChange,
createGraphNodes,
createRemoveChange,
createSelectionChange,
getConnectedEdges,
getDimensions,
getHandleBounds,
getSelectionChanges,
isDef,
isEdge,
isGraphEdge,
isGraphNode,
isNode,
parseEdge,
pointToRendererPoint,
updateEdgeAction,
} from '~/utils'
import { useZoomPanHelper } from '~/composables'
export default (state: State, getters: ComputedGetters): Actions => {
const updateNodeInternals: Actions['updateNodeInternals'] = (ids) => {
state.hooks.updateNodeInternals.trigger(ids)
}
const zoomPanHelper = ref<ReturnType<typeof useZoomPanHelper>>()
state.hooks.paneReady.on(({ id }) => {
zoomPanHelper.value = useZoomPanHelper(id)
})
const paneReady = async () => {
return new Promise<ReturnType<typeof useZoomPanHelper>>((resolve) => {
if (!zoomPanHelper.value) {
until(zoomPanHelper)
.not.toBeUndefined()
.then(() => resolve(zoomPanHelper.value!))
} else {
resolve(zoomPanHelper.value)
}
})
}
const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => {
const changes: NodePositionChange[] = []
dragItems.forEach((node) => {
const change: Partial<NodePositionChange> = {
id: node.id,
type: 'position',
dragging,
from: node.from,
}
if (changed) {
change.computedPosition = node.position
change.position = node.position
if (node.parentNode) {
const parentNode = getters.getNode.value(node.parentNode)
change.position = {
x: change.position.x - (parentNode?.computedPosition?.x ?? 0),
y: change.position.y - (parentNode?.computedPosition?.y ?? 0),
}
}
}
changes.push(change as NodePositionChange)
})
if (changes?.length) {
state.hooks.nodesChange.trigger(changes)
}
}
const updateNodeDimensions: Actions['updateNodeDimensions'] = (updates) => {
if (!state.vueFlowRef) return
const viewportNode = state.vueFlowRef.querySelector('.vue-flow__transformationpane')
if (!viewportNode) return
const changes: NodeDimensionChange[] = updates.reduce<NodeDimensionChange[]>((res, update) => {
const node = getters.getNode.value(update.id)
if (node) {
const dimensions = getDimensions(update.nodeElement)
const style = window.getComputedStyle(viewportNode)
const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform)
const doUpdate =
!!(
dimensions.width &&
dimensions.height &&
(node.dimensions.width !== dimensions.width || node.dimensions.height !== dimensions.height)
) || update.forceUpdate
if (doUpdate) {
node.handleBounds.source = getHandleBounds('.source', update.nodeElement, zoom)
node.handleBounds.target = getHandleBounds('.target', update.nodeElement, zoom)
node.dimensions = dimensions
res.push({
id: node.id,
type: 'dimensions',
dimensions,
})
}
}
return res
}, [])
if (changes.length) state.hooks.nodesChange.trigger(changes)
}
const nodeSelectionHandler = (nodes: GraphNode[], selected: boolean) => {
const nodeIds = nodes.map((n) => n.id)
let changedNodes: NodeChange[]
if (state.multiSelectionActive) changedNodes = nodeIds.map((nodeId) => createSelectionChange(nodeId, selected))
else changedNodes = getSelectionChanges(state.nodes, nodeIds)
if (changedNodes.length) state.hooks.nodesChange.trigger(changedNodes)
}
const edgeSelectionHandler = (edges: GraphEdge[], selected: boolean) => {
const edgeIds = edges.map((e) => e.id)
let changedEdges: EdgeChange[]
if (state.multiSelectionActive) changedEdges = edgeIds.map((edgeId) => createSelectionChange(edgeId, selected))
else changedEdges = getSelectionChanges(state.edges, edgeIds)
if (changedEdges.length) state.hooks.edgesChange.trigger(changedEdges)
}
const addSelectedNodes: Actions['addSelectedNodes'] = (nodes) => {
nodeSelectionHandler(nodes, true)
}
const addSelectedEdges: Actions['addSelectedEdges'] = (edges) => {
edgeSelectionHandler(edges, true)
}
const addSelectedElements: Actions['addSelectedElements'] = (elements) => {
addSelectedNodes(elements.filter(isGraphNode))
addSelectedEdges(elements.filter(isGraphEdge))
}
const removeSelectedNodes: Actions['removeSelectedNodes'] = (nodes) => {
if (!nodes.length) return nodeSelectionHandler(nodes, false)
const nodeIds = nodes.map((n) => n.id)
const changedNodes = nodeIds.map((nodeId) => createSelectionChange(nodeId, false))
if (changedNodes.length) state.hooks.nodesChange.trigger(changedNodes)
}
const removeSelectedEdges: Actions['removeSelectedEdges'] = (edges) => {
if (!edges.length) edgeSelectionHandler(edges, false)
const edgeIds = edges.map((e) => e.id)
const changedEdges = edgeIds.map((edgeId) => createSelectionChange(edgeId, false))
if (changedEdges.length) state.hooks.edgesChange.trigger(changedEdges)
}
const removeSelectedElements: Actions['removeSelectedElements'] = (elements) => {
if (!elements) {
removeSelectedNodes([])
removeSelectedEdges([])
} else {
if (elements.nodes) removeSelectedNodes(elements.nodes.filter(isGraphNode))
if (elements.edges) removeSelectedEdges(elements.edges.filter(isGraphEdge))
}
}
const setMinZoom: Actions['setMinZoom'] = (minZoom: any) => {
state.d3Zoom?.scaleExtent([minZoom, state.maxZoom])
state.minZoom = minZoom
}
const setMaxZoom: Actions['setMaxZoom'] = (maxZoom: any) => {
state.d3Zoom?.scaleExtent([state.minZoom, maxZoom])
state.maxZoom = maxZoom
}
const setTranslateExtent: Actions['setTranslateExtent'] = (translateExtent) => {
state.d3Zoom?.translateExtent(translateExtent)
state.translateExtent = translateExtent
}
const setNodeExtent: Actions['setNodeExtent'] = async (nodeExtent) => {
state.nodeExtent = nodeExtent
if (zoomPanHelper.value) {
const nodeIds = getters.getNodes.value.map((n) => n.id)
updateNodeInternals(nodeIds)
}
}
const setInteractive: Actions['setInteractive'] = (isInteractive) => {
state.nodesDraggable = isInteractive
state.nodesConnectable = isInteractive
state.elementsSelectable = isInteractive
}
const setNodes: Actions['setNodes'] = (nodes, extent?: CoordinateExtent) => {
if (!state.initialized && !nodes.length) return
if (!state.nodes) state.nodes = []
const curr = nodes instanceof Function ? nodes(state.nodes) : nodes
state.nodes = createGraphNodes(curr, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)
}
const setEdges: Actions['setEdges'] = (edges) => {
if (!state.initialized && !edges.length) return
const curr = edges instanceof Function ? edges(state.edges) : edges
state.edges = curr.reduce<GraphEdge[]>((res, edge) => {
const sourceNode = getters.getNode.value(edge.source)!
const targetNode = getters.getNode.value(edge.target)!
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
const missingTarget = !targetNode || typeof targetNode === 'undefined'
if (missingSource) console.warn(`[vue-flow]: Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
if (missingTarget) console.warn(`[vue-flow]: Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
if (missingSource || missingTarget) return res
const storedEdge = getters.getEdge.value(edge.id)
res.push(
shallowReactive({
...parseEdge(edge, Object.assign({}, storedEdge, state.defaultEdgeOptions)),
sourceNode,
targetNode,
}),
)
return res
}, [])
}
const setElements: Actions['setElements'] = (elements, extent) => {
if ((!state.initialized && !elements.length) || !elements) return
const curr = elements instanceof Function ? elements([...state.nodes, ...state.edges]) : elements
setNodes(curr.filter(isNode), extent)
setEdges(curr.filter(isEdge))
}
const addNodes: Actions['addNodes'] = (nodes, extent) => {
const curr = nodes instanceof Function ? nodes(state.nodes) : nodes
const graphNodes = createGraphNodes(curr, getters.getNode.value, state.nodes, extent ?? state.nodeExtent)
const changes = graphNodes.map(createAdditionChange)
if (changes.length) state.hooks.nodesChange.trigger(changes)
}
const addEdges: Actions['addEdges'] = (params) => {
const curr = params instanceof Function ? params(state.edges) : params
const changes = curr.reduce((acc, param) => {
const edge = addEdgeToStore(
{
...param,
...state.defaultEdgeOptions,
},
state.edges,
)
if (edge) {
const sourceNode = getters.getNode.value(edge.source)!
const targetNode = getters.getNode.value(edge.target)!
const missingSource = !sourceNode || typeof sourceNode === 'undefined'
const missingTarget = !targetNode || typeof targetNode === 'undefined'
if (missingSource) console.warn(`[vueflow]: Couldn't create edge for source id: ${edge.source}; edge id: ${edge.id}`)
if (missingTarget) console.warn(`[vueflow]: Couldn't create edge for target id: ${edge.target}; edge id: ${edge.id}`)
if (missingTarget || missingSource) return acc
acc.push(
createAdditionChange<GraphEdge>(
shallowReactive({
...edge,
sourceNode,
targetNode,
}),
),
)
}
return acc
}, [] as EdgeChange[])
if (changes.length) state.hooks.edgesChange.trigger(changes)
}
const removeNodes: Actions['removeNodes'] = (nodes, removeConnectedEdges = true) => {
const curr = nodes instanceof Function ? nodes(state.nodes) : nodes
const nodeChanges: NodeRemoveChange[] = []
const edgeChanges: EdgeRemoveChange[] = []
curr.forEach((item) => {
nodeChanges.push(createRemoveChange(typeof item === 'string' ? item : item.id))
if (removeConnectedEdges) {
const connections = getConnectedEdges([typeof item === 'string' ? ({ id: item } as any) : item], state.edges)
edgeChanges.push(...connections.map((connection) => createRemoveChange(connection.id)))
}
})
if (nodeChanges.length) {
state.hooks.nodesChange.trigger(nodeChanges)
}
if (edgeChanges.length) {
state.hooks.edgesChange.trigger(edgeChanges)
}
}
const removeEdges: Actions['removeEdges'] = (edges) => {
const curr = edges instanceof Function ? edges(state.edges) : edges
const changes: EdgeRemoveChange[] = []
curr.forEach((item) => {
changes.push(createRemoveChange(typeof item === 'string' ? item : item.id))
})
state.hooks.edgesChange.trigger(changes)
}
const nodeIds = $computed(() => state.nodes.map((n) => n.id))
const edgeIds = $computed(() => state.edges.map((e) => e.id))
const findNode: Actions['findNode'] = (id) => {
if (state.nodes && !nodeIds.length) return state.nodes.find((node) => node.id === id)
return state.nodes[nodeIds.indexOf(id)]
}
const findEdge: Actions['findEdge'] = (id) => {
if (state.edges && !edgeIds.length) return state.edges.find((edge) => edge.id === id)
return state.edges[edgeIds.indexOf(id)]
}
const updateEdge: Actions['updateEdge'] = (oldEdge, newConnection) => updateEdgeAction(oldEdge, newConnection, state.edges)
const applyNodeChanges: Actions['applyNodeChanges'] = (changes) => applyChanges(changes, state.nodes)
const applyEdgeChanges: Actions['applyEdgeChanges'] = (changes) => applyChanges(changes, state.edges)
const startConnection: Actions['startConnection'] = (startHandle, position, event) => {
state.connectionStartHandle = startHandle
if (position) state.connectionPosition = position
state.hooks.connectStart.trigger({
event,
nodeId: startHandle.nodeId,
handleId: startHandle.handleId,
handleType: startHandle.type,
})
}
const updateConnection: Actions['updateConnection'] = (position) => {
state.connectionPosition = position
}
const endConnection: Actions['endConnection'] = (event) => {
state.connectionPosition = { x: NaN, y: NaN }
state.connectionStartHandle = null
state.hooks.connectEnd.trigger(event)
}
const setState: Actions['setState'] = (options) => {
const opts = options instanceof Function ? options(state) : options
const skip: (keyof typeof opts)[] = [
'modelValue',
'nodes',
'edges',
'maxZoom',
'minZoom',
'translateExtent',
'nodeExtent',
'hooks',
]
if (typeof opts.modelValue !== 'undefined') setElements(opts.modelValue, opts.nodeExtent ?? state.nodeExtent)
if (typeof opts.nodes !== 'undefined') setNodes(opts.nodes, opts.nodeExtent ?? state.nodeExtent)
if (typeof opts.edges !== 'undefined') setEdges(opts.edges)
const setSkippedOptions = () => {
if (typeof opts.maxZoom !== 'undefined') setMaxZoom(opts.maxZoom)
if (typeof opts.minZoom !== 'undefined') setMinZoom(opts.minZoom)
if (typeof opts.translateExtent !== 'undefined') setTranslateExtent(opts.translateExtent)
if (typeof opts.nodeExtent !== 'undefined') setNodeExtent(opts.nodeExtent)
}
Object.keys(opts).forEach((o) => {
const option = opts[o as keyof typeof opts]
if (!skip.includes(o as keyof typeof opts) && isDef(option)) (<any>state)[o] = option
})
if (!state.d3Zoom) {
until(() => state.d3Zoom)
.not.toBeUndefined()
.then(setSkippedOptions)
} else {
setSkippedOptions()
}
if (!state.initialized) state.initialized = true
}
const toObject = () => {
// we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
return JSON.parse(
JSON.stringify({
nodes: state.nodes,
edges: state.edges,
position: [state.viewport.x, state.viewport.y],
zoom: state.viewport.zoom,
} as FlowExportObject),
)
}
return {
updateNodePositions,
updateNodeDimensions,
setElements,
setNodes,
setEdges,
addNodes,
addEdges,
removeNodes,
removeEdges,
findNode,
findEdge,
updateEdge,
applyEdgeChanges,
applyNodeChanges,
addSelectedElements,
addSelectedNodes,
addSelectedEdges,
setMinZoom,
setMaxZoom,
setTranslateExtent,
setNodeExtent,
removeSelectedElements,
removeSelectedNodes,
removeSelectedEdges,
startConnection,
updateConnection,
endConnection,
setInteractive,
setState,
fitView: async (params = { padding: 0.1 }) => {
const { fitView } = await paneReady()
fitView(params)
},
zoomIn: async (options) => {
const { zoomIn } = await paneReady()
zoomIn(options)
},
zoomOut: async (options) => {
const { zoomOut } = await paneReady()
zoomOut(options)
},
zoomTo: async (zoomLevel, options) => {
const { zoomTo } = await paneReady()
zoomTo(zoomLevel, options)
},
setTransform: async (transform, options) => {
const { setTransform } = await paneReady()
setTransform(transform, options)
},
getTransform: () => ({
x: state.viewport.x,
y: state.viewport.y,
zoom: state.viewport.zoom,
}),
setCenter: async (x, y, options) => {
const { setCenter } = await paneReady()
setCenter(x, y, options)
},
fitBounds: async (bounds, options) => {
const { fitBounds } = await paneReady()
fitBounds(bounds, options)
},
project: (position) => pointToRendererPoint(position, state.viewport, state.snapToGrid, state.snapGrid),
toObject,
updateNodeInternals,
$reset: () => {
setState(useState())
},
$destroy: () => {},
}
}
+128
View File
@@ -0,0 +1,128 @@
import { defaultEdgeTypes, defaultNodeTypes } from './state'
import type { ComputedGetters, GraphEdge, GraphNode, State } from '~/types'
import { getNodesInside, isEdgeVisible } from '~/utils'
export default (state: State): ComputedGetters => {
const nodeIds = computed(() => state.nodes.map((n) => n.id))
const edgeIds = computed(() => state.edges.map((e) => e.id))
const getNode: ComputedGetters['getNode'] = computed(() => (id: string) => {
if (state.nodes && !nodeIds.value.length) return state.nodes.find((node) => node.id === id)
return state.nodes[nodeIds.value.indexOf(id)]
})
const getEdge: ComputedGetters['getEdge'] = computed(() => (id: string) => {
if (state.edges && !edgeIds.value.length) return state.edges.find((edge) => edge.id === id)
return state.edges[edgeIds.value.indexOf(id)]
})
const getEdgeTypes = computed(() => {
const edgeTypes: Record<string, any> = {
...defaultEdgeTypes,
...state.edgeTypes,
}
const keys = Object.keys(edgeTypes)
state.edges?.forEach((e) => e.type && !keys.includes(e.type) && (edgeTypes[e.type] = e.type))
return edgeTypes
})
const getNodeTypes = computed(() => {
const nodeTypes: Record<string, any> = {
...defaultNodeTypes,
...state.nodeTypes,
}
const keys = Object.keys(nodeTypes)
state.nodes?.forEach((n) => n.type && !keys.includes(n.type) && (nodeTypes[n.type] = n.type))
return nodeTypes
})
const getNodes = computed<GraphNode[]>(() => {
const nodes = state.nodes.filter((n) => !n.hidden)
return state.onlyRenderVisibleElements
? nodes &&
getNodesInside(
nodes,
{
x: 0,
y: 0,
width: state.dimensions.width,
height: state.dimensions.height,
},
state.viewport,
true,
)
: nodes ?? []
})
const edgeHidden = (e: GraphEdge, source?: GraphNode, target?: GraphNode) => {
source = source ?? getNode.value(e.source)
target = target ?? getNode.value(e.target)
if (!source || !target) {
state.edges = state.edges.filter((edge) => edge.id !== e.id)
console.warn(`[vue-flow]: Orphaned edge ${e.id} removed.`)
return
}
return (
!e.hidden &&
target &&
!target.hidden &&
source &&
!source.hidden &&
source.dimensions.width &&
source.dimensions.height &&
target.dimensions.width &&
target.dimensions.height
)
}
const getEdges = computed<GraphEdge[]>(() => {
if (!state.onlyRenderVisibleElements) return state.edges.filter((edge) => edgeHidden(edge))
return state.edges.filter((e) => {
const source = getNode.value(e.source)!
const target = getNode.value(e.target)!
return (
edgeHidden(e, source, target) &&
isEdgeVisible({
sourcePos: source.computedPosition || { x: 0, y: 0 },
targetPos: target.computedPosition || { x: 0, y: 0 },
sourceWidth: source.dimensions.width,
sourceHeight: source.dimensions.height,
targetWidth: target.dimensions.width,
targetHeight: target.dimensions.height,
width: state.dimensions.width,
height: state.dimensions.height,
viewport: state.viewport,
})
)
})
})
const getElements: ComputedGetters['getElements'] = computed(() => [...getNodes.value, ...getEdges.value])
const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => state.nodes.filter((n) => n.selected))
const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => state.edges.filter((e) => e.selected))
const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [
...(getSelectedNodes.value ?? []),
...(getSelectedEdges.value ?? []),
])
return {
getNode,
getEdge,
getElements,
getEdgeTypes,
getNodeTypes,
getEdges,
getNodes,
getSelectedElements,
getSelectedNodes,
getSelectedEdges,
}
}
+65
View File
@@ -0,0 +1,65 @@
import type { Ref } from 'vue'
import type { Emits, FlowHooks } from '~/types'
// flow event hooks
export const createHooks = (): FlowHooks => ({
edgesChange: createEventHook(),
nodesChange: createEventHook(),
nodeDoubleClick: createEventHook(),
nodeClick: createEventHook(),
nodeMouseEnter: createEventHook(),
nodeMouseMove: createEventHook(),
nodeMouseLeave: createEventHook(),
nodeContextMenu: createEventHook(),
nodeDragStart: createEventHook(),
nodeDrag: createEventHook(),
nodeDragStop: createEventHook(),
miniMapNodeClick: createEventHook(),
miniMapNodeDoubleClick: createEventHook(),
miniMapNodeMouseEnter: createEventHook(),
miniMapNodeMouseMove: createEventHook(),
miniMapNodeMouseLeave: createEventHook(),
connect: createEventHook(),
connectStart: createEventHook(),
connectEnd: createEventHook(),
paneReady: createEventHook(),
move: createEventHook(),
moveStart: createEventHook(),
moveEnd: createEventHook(),
selectionDragStart: createEventHook(),
selectionDrag: createEventHook(),
selectionDragStop: createEventHook(),
selectionContextMenu: createEventHook(),
paneScroll: createEventHook(),
paneClick: createEventHook(),
paneContextMenu: createEventHook(),
paneMouseEnter: createEventHook(),
paneMouseMove: createEventHook(),
paneMouseLeave: createEventHook(),
edgeContextMenu: createEventHook(),
edgeMouseEnter: createEventHook(),
edgeMouseMove: createEventHook(),
edgeMouseLeave: createEventHook(),
edgeDoubleClick: createEventHook(),
edgeClick: createEventHook(),
edgeUpdateStart: createEventHook(),
edgeUpdate: createEventHook(),
edgeUpdateEnd: createEventHook(),
updateNodeInternals: createEventHook(),
})
export default (emit: Emits, hooks: Ref<FlowHooks>) => {
onBeforeMount(() => {
for (const [key, value] of Object.entries(hooks.value)) {
const listener = (data: any) => {
emit(key as Emits extends (event: infer Event) => void ? Event : never, data)
}
value.on(listener)
tryOnScopeDispose(() => {
value.off(listener)
})
}
})
}
+4
View File
@@ -0,0 +1,4 @@
export { default as useHooks, createHooks } from './hooks'
export { default as useActions } from './actions'
export { default as useState, defaultEdgeTypes, defaultNodeTypes } from './state'
export { default as useGetters } from './getters'
+129
View File
@@ -0,0 +1,129 @@
import { createHooks } from './hooks'
import type { DefaultEdgeTypes, DefaultNodeTypes, FlowOptions, State } from '~/types'
import { ConnectionLineType, ConnectionMode, PanOnScrollMode } from '~/types'
import {
BezierEdge,
DefaultNode,
InputNode,
OutputNode,
SimpleBezierEdge,
SmoothStepEdge,
StepEdge,
StraightEdge,
} from '~/components'
export const defaultNodeTypes: DefaultNodeTypes = {
input: InputNode,
default: DefaultNode,
output: OutputNode,
}
export const defaultEdgeTypes: DefaultEdgeTypes = {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge,
smoothstep: SmoothStepEdge,
simplebezier: SimpleBezierEdge,
}
const isDef = <T>(val: T): val is NonNullable<T> => typeof val !== 'undefined'
const defaultState = (): State => ({
vueFlowRef: null,
viewportRef: null,
nodes: [],
edges: [],
nodeTypes: {},
edgeTypes: {},
initialized: false,
dimensions: {
width: 0,
height: 0,
},
viewport: { x: 0, y: 0, zoom: 1 },
d3Zoom: null,
d3Selection: null,
d3ZoomHandler: null,
minZoom: 0.5,
maxZoom: 2,
translateExtent: [
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
],
nodeExtent: [
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
],
preventScrolling: true,
zoomOnScroll: true,
zoomOnPinch: true,
zoomOnDoubleClick: true,
panOnScroll: false,
panOnScrollSpeed: 0.5,
panOnScrollMode: PanOnScrollMode.Free,
panOnDrag: true,
edgeUpdaterRadius: 10,
onlyRenderVisibleElements: false,
defaultZoom: 1,
defaultPosition: [0, 0],
nodesSelectionActive: false,
userSelectionActive: false,
defaultMarkerColor: '#b1b1b7',
connectionLineStyle: {},
connectionLineType: ConnectionLineType.Bezier,
connectionLineOptions: {
type: ConnectionLineType.Bezier,
style: {},
},
connectionMode: ConnectionMode.Loose,
connectionStartHandle: null,
connectionPosition: { x: NaN, y: NaN },
connectOnClick: true,
snapGrid: [15, 15],
snapToGrid: false,
edgesUpdatable: false,
nodesConnectable: true,
nodesDraggable: true,
elementsSelectable: true,
selectNodesOnDrag: true,
multiSelectionActive: false,
selectionKeyCode: 'Shift',
multiSelectionKeyCode: 'Meta',
zoomActivationKeyCode: 'Meta',
deleteKeyCode: 'Backspace',
hooks: createHooks(),
applyDefault: true,
autoConnect: false,
fitViewOnInit: false,
noDragClassName: 'nodrag',
noWheelClassName: 'nowheel',
noPanClassName: 'nopan',
defaultEdgeOptions: undefined,
elevateEdgesOnSelect: false,
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : '-',
})
export default (opts?: FlowOptions): State => {
const state = defaultState()
if (opts) {
Object.keys(opts).forEach((o) => {
const option = opts[o as keyof typeof opts]
if (isDef(option)) (state as any)[o] = option
})
}
return state
}