refactor(core): rename core pkg dir to core
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
<script lang="ts" setup>
|
||||
import type { CSSProperties, EffectScope } from 'vue'
|
||||
import EdgeWrapper from '../../components/Edges/Wrapper'
|
||||
import ConnectionLine from '../../components/ConnectionLine/ConnectionLine.vue'
|
||||
import { useEdgeHooks, useHandle, useVueFlow } from '../../composables'
|
||||
import { connectionExists, groupEdgesByZLevel } from '../../utils'
|
||||
import type { EdgeComponent, EdgeUpdatable, GraphEdge } from '../../types'
|
||||
import { Slots } from '../../context'
|
||||
import MarkerDefinitions from './MarkerDefinitions.vue'
|
||||
|
||||
const slots = inject(Slots)
|
||||
|
||||
const {
|
||||
emits,
|
||||
connectionMode,
|
||||
edgeUpdaterRadius,
|
||||
onPaneReady,
|
||||
connectionStartHandle,
|
||||
nodesConnectable,
|
||||
edgesUpdatable,
|
||||
elementsSelectable,
|
||||
getSelectedNodes,
|
||||
nodesSelectionActive,
|
||||
getNode,
|
||||
getNodes,
|
||||
getEdges,
|
||||
getEdgeTypes,
|
||||
addSelectedEdges,
|
||||
noPanClassName,
|
||||
elevateEdgesOnSelect,
|
||||
} = $(useVueFlow())
|
||||
|
||||
const selectable = (s?: boolean) => (typeof s === 'undefined' ? elementsSelectable : s)
|
||||
|
||||
const updatable = (u?: EdgeUpdatable) => (typeof u === 'undefined' ? edgesUpdatable : u)
|
||||
|
||||
const updating = ref<string>()
|
||||
|
||||
const sourceNode = $(
|
||||
controlledComputed(
|
||||
() => connectionStartHandle?.nodeId,
|
||||
() => {
|
||||
if (connectionStartHandle?.nodeId) return getNode(connectionStartHandle.nodeId)
|
||||
return false
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
const connectionLineVisible = $(
|
||||
controlledComputed(
|
||||
() => connectionStartHandle?.nodeId,
|
||||
() =>
|
||||
!!(
|
||||
sourceNode &&
|
||||
(typeof sourceNode.connectable === 'undefined' ? nodesConnectable : sourceNode.connectable) &&
|
||||
connectionStartHandle?.nodeId &&
|
||||
connectionStartHandle?.type
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
const hooks = $ref<Record<string, ReturnType<typeof useEdgeHooks>>>({})
|
||||
|
||||
let groups = $ref<ReturnType<typeof groupEdgesByZLevel>>([])
|
||||
|
||||
let scope: EffectScope | null = effectScope()
|
||||
|
||||
onPaneReady(() => {
|
||||
if (!scope) scope = effectScope()
|
||||
|
||||
scope.run(() => {
|
||||
watch(
|
||||
[$$(getSelectedNodes), $$(getEdges)],
|
||||
() => {
|
||||
getEdges.forEach((edge) => {
|
||||
if (hooks[edge.id]) return
|
||||
hooks[edge.id] = useEdgeHooks(edge, emits)
|
||||
})
|
||||
|
||||
if (elevateEdgesOnSelect) {
|
||||
nextTick(() => (groups = groupEdgesByZLevel(getEdges, getNode)))
|
||||
} else {
|
||||
groups = [
|
||||
{
|
||||
isMaxLevel: true,
|
||||
edges: getEdges,
|
||||
level: 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
scope?.stop()
|
||||
scope = null
|
||||
})
|
||||
|
||||
const getType = (type?: string, template?: GraphEdge['template']) => {
|
||||
const name = type || 'default'
|
||||
let edgeType = template ?? getEdgeTypes[name]
|
||||
const instance = getCurrentInstance()
|
||||
|
||||
if (typeof edgeType === 'string') {
|
||||
if (instance) {
|
||||
const components = Object.keys(instance.appContext.components)
|
||||
if (components && components.includes(name)) {
|
||||
edgeType = resolveComponent(name, false) as EdgeComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
if (edgeType && typeof edgeType !== 'string') return edgeType
|
||||
|
||||
const slot = slots?.[`edge-${name}`]
|
||||
if (!slot?.({})) {
|
||||
console.warn(`[vueflow]: Edge type "${type}" not found and no edge-slot detected. Using fallback type "default".`)
|
||||
return false
|
||||
}
|
||||
|
||||
return slot
|
||||
}
|
||||
|
||||
const onEdgeClick = (event: MouseEvent, edge: GraphEdge) => {
|
||||
const data = { event, edge }
|
||||
if (selectable(edge.selectable)) {
|
||||
$$(nodesSelectionActive).value = false
|
||||
|
||||
addSelectedEdges([edge])
|
||||
}
|
||||
hooks[edge.id].emit.click(data)
|
||||
}
|
||||
|
||||
const onEdgeContextMenu = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.contextMenu({ event, edge })
|
||||
|
||||
const onDoubleClick = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.doubleClick({ event, edge })
|
||||
|
||||
const onEdgeMouseEnter = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.mouseEnter({ event, edge })
|
||||
|
||||
const onEdgeMouseMove = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.mouseMove({ event, edge })
|
||||
|
||||
const onEdgeMouseLeave = (event: MouseEvent, edge: GraphEdge) => hooks[edge.id].emit.mouseLeave({ event, edge })
|
||||
|
||||
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent, edge: GraphEdge) => {
|
||||
updating.value = edge.id
|
||||
handleEdgeUpdater(event, edge, true)
|
||||
}
|
||||
|
||||
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent, edge: GraphEdge) => {
|
||||
updating.value = edge.id
|
||||
handleEdgeUpdater(event, edge, false)
|
||||
}
|
||||
|
||||
const { onMouseDown } = useHandle()
|
||||
|
||||
const handleEdgeUpdater = (event: MouseEvent, edge: GraphEdge, isSourceHandle: boolean) => {
|
||||
const nodeId = isSourceHandle ? edge.target : edge.source
|
||||
const handleId = (isSourceHandle ? edge.targetHandle : edge.sourceHandle) ?? ''
|
||||
|
||||
hooks[edge.id].emit.updateStart({ event, edge })
|
||||
|
||||
onMouseDown(
|
||||
event,
|
||||
handleId,
|
||||
nodeId,
|
||||
isSourceHandle,
|
||||
undefined,
|
||||
isSourceHandle ? 'target' : 'source',
|
||||
(connection) => {
|
||||
if (!connectionExists(connection, getEdges)) hooks[edge.id].emit.update({ edge, connection })
|
||||
},
|
||||
() => {
|
||||
hooks[edge.id].emit.updateEnd({ event, edge })
|
||||
updating.value = ''
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
const getClass = (edge: GraphEdge) => {
|
||||
const extraClass = edge.class instanceof Function ? edge.class(edge) : edge.class
|
||||
return [noPanClassName, extraClass]
|
||||
}
|
||||
|
||||
const getStyle = (edge: GraphEdge) => (edge.style instanceof Function ? edge.style(edge) : edge.style) as CSSProperties
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Edges',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg v-for="group of groups" :key="group.level" class="vue-flow__edges vue-flow__container" :style="`z-index: ${group.level}`">
|
||||
<MarkerDefinitions v-if="group.isMaxLevel" />
|
||||
<g>
|
||||
<EdgeWrapper
|
||||
v-for="edge of group.edges"
|
||||
:id="edge.id"
|
||||
:key="edge.id"
|
||||
:type="getType(edge.type, edge.template)"
|
||||
:name="edge.type || 'default'"
|
||||
:source="edge.source"
|
||||
:target="edge.target"
|
||||
:target-handle-id="edge.targetHandle"
|
||||
:source-handle-id="edge.sourceHandle"
|
||||
:source-node="getNode(edge.source)"
|
||||
:target-node="getNode(edge.target)"
|
||||
:label="edge.label"
|
||||
:data="edge.data"
|
||||
:events="{ ...edge.events, ...hooks[edge.id].on }"
|
||||
:animated="edge.animated"
|
||||
:selectable="selectable(edge.selectable)"
|
||||
:selected="edge.selected"
|
||||
:updatable="updatable(edge.updatable)"
|
||||
:updating="edge.id === updating"
|
||||
:label-style="edge.labelStyle"
|
||||
:label-show-bg="edge.labelShowBg"
|
||||
:label-bg-style="edge.labelBgStyle"
|
||||
:label-bg-padding="edge.labelBgPadding"
|
||||
:label-bg-border-radius="edge.labelBgBorderRadius"
|
||||
:connection-mode="connectionMode"
|
||||
:edge-updater-radius="edgeUpdaterRadius"
|
||||
:marker-end="edge.markerEnd"
|
||||
:marker-start="edge.markerStart"
|
||||
:style="getStyle(edge)"
|
||||
:class="getClass(edge)"
|
||||
@click="onEdgeClick($event, edge)"
|
||||
@dblclick="onDoubleClick($event, edge)"
|
||||
@contextmenu="onEdgeContextMenu($event, edge)"
|
||||
@mouseenter="onEdgeMouseEnter($event, edge)"
|
||||
@mousemove="onEdgeMouseMove($event, edge)"
|
||||
@mouseleave="onEdgeMouseLeave($event, edge)"
|
||||
@source-mousedown="onEdgeUpdaterSourceMouseDown($event, edge)"
|
||||
@target-mousedown="onEdgeUpdaterTargetMouseDown($event, edge)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg v-if="connectionLineVisible && !!sourceNode" class="vue-flow__edges vue-flow__connectionline vue-flow__container">
|
||||
<ConnectionLine :source-node="sourceNode" />
|
||||
</svg>
|
||||
</template>
|
||||
@@ -0,0 +1,54 @@
|
||||
<script lang="ts" setup>
|
||||
import { MarkerType } from '../../types/edge'
|
||||
import type { MarkerProps } from '../../types/edge'
|
||||
|
||||
const {
|
||||
id,
|
||||
type,
|
||||
width = 12.5,
|
||||
height = 12.5,
|
||||
markerUnits = 'strokeWidth',
|
||||
orient = 'auto-start-reverse',
|
||||
strokeWidth = 1,
|
||||
color = 'none',
|
||||
} = defineProps<MarkerProps>()
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'MarkerType',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<marker
|
||||
:id="id"
|
||||
class="vue-flow__arrowhead"
|
||||
viewBox="-10 -10 20 20"
|
||||
refX="0"
|
||||
refY="0"
|
||||
:markerWidth="`${width}`"
|
||||
:markerHeight="`${height}`"
|
||||
:markerUnits="markerUnits"
|
||||
:orient="orient"
|
||||
>
|
||||
<polyline
|
||||
v-if="type === MarkerType.ArrowClosed"
|
||||
:stroke="color"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
:stroke-width="strokeWidth"
|
||||
:fill="color"
|
||||
points="-5,-4 0,0 -5,4 -5,-4"
|
||||
/>
|
||||
<polyline
|
||||
v-if="type === MarkerType.Arrow"
|
||||
:stroke="color"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
:stroke-width="strokeWidth"
|
||||
fill="none"
|
||||
points="-5,-4 0,0 -5,4"
|
||||
/>
|
||||
</marker>
|
||||
</template>
|
||||
@@ -0,0 +1,56 @@
|
||||
<script lang="ts" setup>
|
||||
import { useVueFlow } from '../../composables'
|
||||
import type { EdgeMarkerType, MarkerProps, MarkerType } from '../../types/edge'
|
||||
import { getMarkerId } from '../../utils'
|
||||
import Marker from './Marker.vue'
|
||||
|
||||
const { edges, connectionLineOptions, defaultMarkerColor: defaultColor } = $(useVueFlow())
|
||||
|
||||
const markers = computed(() => {
|
||||
const ids: string[] = []
|
||||
const markers: MarkerProps[] = []
|
||||
|
||||
const createMarkers = (marker?: EdgeMarkerType) => {
|
||||
if (marker) {
|
||||
const markerId = getMarkerId(marker)
|
||||
if (!ids.includes(markerId)) {
|
||||
if (typeof marker === 'object') markers.push({ ...marker, id: markerId, color: marker.color || defaultColor })
|
||||
else markers.push({ id: markerId, color: defaultColor, type: marker as MarkerType })
|
||||
ids.push(markerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
;[connectionLineOptions.markerEnd, connectionLineOptions.markerStart].forEach(createMarkers)
|
||||
|
||||
edges.reduce<MarkerProps[]>((markers, edge) => {
|
||||
;[edge.markerStart, edge.markerEnd].forEach(createMarkers)
|
||||
return markers.sort((a, b) => a.id.localeCompare(b.id))
|
||||
}, markers)
|
||||
|
||||
return markers
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'MarkerDefinitions',
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<defs>
|
||||
<Marker
|
||||
v-for="marker of markers"
|
||||
:id="marker.id"
|
||||
:key="marker.id"
|
||||
:type="marker.type"
|
||||
:color="marker.color"
|
||||
:width="marker.width"
|
||||
:height="marker.height"
|
||||
:markerUnits="marker.markerUnits"
|
||||
:stroke-width="marker.strokeWidth"
|
||||
:orient="marker.orient"
|
||||
/>
|
||||
</defs>
|
||||
</template>
|
||||
Reference in New Issue
Block a user