update: Add slots to CustomConnectionLine.vue, Edge.vue, Node.vue

This commit is contained in:
Braks
2021-10-20 22:39:54 +02:00
parent b3d276bfb8
commit 9d9a90e9a7
25 changed files with 363 additions and 391 deletions
+13 -13
View File
@@ -4,25 +4,20 @@ import { getSourceTargetNodes } from './utils'
import MarkerDefinitions from './MarkerDefinitions.vue'
import Edge from '~/components/Edges/Edge.vue'
import ConnectionLine from '~/components/ConnectionLine/ConnectionLine.vue'
import { ConnectionLineType, CustomConnectionLine, Dimensions, EdgeType, Transform } from '~/types'
import { ConnectionLineType, EdgeType } from '~/types'
import { Store } from '~/context'
interface EdgeRendererProps {
edgeTypes: Record<string, EdgeType>
dimensions: Dimensions
transform: Transform
connectionLineType?: ConnectionLineType
connectionLineStyle?: CSSProperties
customConnectionLine?: CustomConnectionLine
arrowHeadColor?: string
markerEndId?: string
edgeUpdaterRadius?: number
}
const props = withDefaults(defineProps<EdgeRendererProps>(), {
transform: () => [0, 0, 1],
arrowHeadColor: '#b1b1b7',
dimensions: () => ({ width: 0, height: 0 }),
connectionLineType: ConnectionLineType.Bezier,
edgeUpdaterRadius: 10,
})
@@ -35,10 +30,10 @@ const connectionLineVisible = computed(
)
</script>
<template>
<svg :width="props.dimensions.width" :height="props.dimensions.height" class="revue-flow__edges">
<svg :width="store.dimensions.width" :height="store.dimensions.height" class="revue-flow__edges">
<MarkerDefinitions :color="props.arrowHeadColor" />
<g
:transform="props.transform.length && `translate(${props.transform[0]},${props.transform[1]}) scale(${props.transform[2]})`"
:transform="store.transform.length && `translate(${store.transform[0]},${store.transform[1]}) scale(${store.transform[2]})`"
>
<template v-for="edge of store.edges" :key="edge.id">
<Edge
@@ -46,19 +41,24 @@ const connectionLineVisible = computed(
:edge="edge"
:nodes="getSourceTargetNodes(edge, store.nodes)"
:type="props.edgeTypes[edge.type || 'default']"
:dimensions="props.dimensions"
:transform="props.transform"
:marker-end-id="props.markerEndId"
:edge-updater-radius="props.edgeUpdaterRadius"
/>
>
<template #default="edgeProps">
<slot name="edge" v-bind="edgeProps"></slot>
</template>
</Edge>
</template>
<ConnectionLine
v-if="connectionLineVisible"
:source-node="sourceNode"
:connection-line-style="props.connectionLineStyle"
:connection-line-type="props.connectionLineType"
:custom-connection-line="props.customConnectionLine"
/>
>
<template #default="customConnectionLineProps">
<slot name="custom-connection-line" v-bind="customConnectionLineProps"></slot>
</template>
</ConnectionLine>
</g>
</svg>
</template>
+26 -22
View File
@@ -13,12 +13,11 @@ import {
PanOnScrollMode,
NodeType,
EdgeType,
CustomConnectionLine,
KeyCode,
TranslateExtent,
NodeExtent,
} from '~/types'
import configureStore from '~/store/configure-store'
import useFlowStore from '~/store/useFlowStore'
import { initialState } from '~/store'
import { DefaultNode, InputNode, OutputNode } from '~/components/Nodes'
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge } from '~/components/Edges'
@@ -34,7 +33,6 @@ export interface FlowProps {
connectionMode?: ConnectionMode
connectionLineType?: ConnectionLineType
connectionLineStyle?: CSSProperties
customConnectionLine?: CustomConnectionLine
deleteKeyCode?: KeyCode
selectionKeyCode?: KeyCode
multiSelectionKeyCode?: KeyCode
@@ -118,7 +116,7 @@ const defaultEdgeTypes: Record<string, EdgeType> = {
let store = inject(Store)!
if (!store) {
store = configureStore({
store = useFlowStore({
...initialState,
...props,
})()
@@ -160,25 +158,31 @@ const edgeTypes = createEdgeTypes({ ...defaultEdgeTypes, ...props.edgeTypes })
:pan-on-scroll-mode="props.panOnScrollMode"
:pane-moveable="props.paneMoveable"
>
<template #default="{ transform, dimensions }">
<SelectionPane
:delete-key-code="props.deleteKeyCode"
:multi-selection-key-code="props.multiSelectionKeyCode"
:selection-key-code="props.selectionKeyCode"
<SelectionPane
:delete-key-code="props.deleteKeyCode"
:multi-selection-key-code="props.multiSelectionKeyCode"
:selection-key-code="props.selectionKeyCode"
>
<NodeRenderer :node-types="nodeTypes">
<template #default="nodeProps">
<slot name="node" v-bind="nodeProps"></slot>
</template>
</NodeRenderer>
<EdgeRenderer
:connection-line-type="props.connectionLineType"
:connection-line-style="props.connectionLineStyle"
:arrow-head-color="props.arrowHeadColor"
:marker-end-id="props.markerEndId"
:edge-types="edgeTypes"
>
<NodeRenderer :node-types="nodeTypes" :transform="transform" :dimensions="dimensions" />
<EdgeRenderer
:connection-line-type="props.connectionLineType"
:connection-line-style="props.connectionLineStyle"
:custom-connection-line="props.customConnectionLine"
:arrow-head-color="props.arrowHeadColor"
:marker-end-id="props.markerEndId"
:edge-types="edgeTypes"
:transform="transform"
:dimensions="dimensions"
/>
</SelectionPane>
</template>
<template #edge="edgeProps">
<slot name="edge" v-bind="edgeProps"></slot>
</template>
<template #custom-connection-line="customConnectionLineProps">
<slot name="custom-connection-line" v-bind="customConnectionLineProps"></slot>
</template>
</EdgeRenderer>
</SelectionPane>
</ZoomPane>
<slot></slot>
</div>
+12 -13
View File
@@ -1,19 +1,14 @@
<script lang="ts" setup>
import Node from '~/components/Nodes/Node.vue'
import { NodeType, Node as TNode, Transform, Dimensions } from '~/types'
import { NodeType, Node as TNode } from '~/types'
import { getNodesInside } from '~/utils/graph'
import { Store } from '~/context'
interface NodeRendererProps {
nodeTypes: Record<string, NodeType>
dimensions: Dimensions
transform: Transform
}
const props = withDefaults(defineProps<NodeRendererProps>(), {
transform: () => [0, 0, 1],
dimensions: () => ({ width: 0, height: 0 }),
})
const props = defineProps<NodeRendererProps>()
const store = inject(Store)!
@@ -25,10 +20,10 @@ const getNodes = computed(() =>
{
x: 0,
y: 0,
width: props.dimensions.width,
height: props.dimensions.height,
width: store.dimensions.width,
height: store.dimensions.height,
},
props.transform,
store.transform,
true,
)
: store.nodes,
@@ -48,20 +43,24 @@ const selected = (nodeId: string) => store.selectedElements?.some(({ id }) => id
<template>
<div
class="revue-flow__nodes"
:style="{ transform: `translate(${props.transform[0]}px,${props.transform[1]}px) scale(${props.transform[2]})` }"
:style="{ transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})` }"
>
<template v-for="node of getNodes" :key="node.id">
<Node
v-if="!node.isHidden"
:node="node"
:type="type(node)"
:scale="props.transform[2]"
:scale="store.transform[2]"
:snap-grid="store.snapToGrid ? store.snapGrid : undefined"
:selected="selected(node.id)"
:selectable="node.selectable || store.elementsSelectable"
:connectable="node.connectable || store.nodesConnectable"
:draggable="node.draggable || store.nodesDraggable"
/>
>
<template #default="nodeProps">
<slot v-bind="nodeProps"></slot>
</template>
</Node>
</template>
</div>
</template>
+20 -11
View File
@@ -1,10 +1,10 @@
<script lang="ts" setup>
import useKeyPress from '~/composables/useKeyPress'
import { KeyCode } from '~/types'
import useGlobalKeyHandler from '~/composables/useGlobalKeyHandler'
import { ElementId, FlowElement, KeyCode } from '~/types'
import NodesSelection from '~/components/NodesSelection/NodesSelection.vue'
import UserSelection from '~/components/UserSelection/UserSelection.vue'
import { Hooks, Store } from '~/context'
import { getConnectedEdges, isNode } from '~/utils/graph'
interface SelectionPaneProps {
selectionKeyCode?: KeyCode
@@ -18,7 +18,6 @@ const props = withDefaults(defineProps<SelectionPaneProps>(), {
})
const store = inject(Store)!
const hooks = inject(Hooks)!
const keyPressed = useKeyPress(props.selectionKeyCode)
const onClick = (event: MouseEvent) => {
hooks.paneClick.trigger(event)
@@ -30,18 +29,28 @@ const onContextMenu = (event: MouseEvent) => hooks.paneContextMenu.trigger(event
const onWheel = (event: WheelEvent) => hooks.paneScroll.trigger(event)
useGlobalKeyHandler({
onElementsRemove: hooks.elementsRemove.trigger,
deleteKeyCode: props.deleteKeyCode,
multiSelectionKeyCode: props.multiSelectionKeyCode,
const selectionKeyPresed = useKeyPress(props.selectionKeyCode)
useKeyPress(props.deleteKeyCode, (keyPressed) => {
if (keyPressed && store.selectedElements) {
const selectedNodes = store.selectedElements.filter(isNode)
const connectedEdges = getConnectedEdges(selectedNodes, store.edges)
const elementsToRemove = [...store.selectedElements, ...connectedEdges].reduce(
(res, item) => res.set(item.id, item),
new Map<ElementId, FlowElement>(),
)
hooks.elementsRemove.trigger(Array.from(elementsToRemove.values()))
store.unsetNodesSelection()
store.resetSelectedElements()
}
})
const userSelectionVisible = computed(() => keyPressed.value && (store.selectionActive || store.elementsSelectable))
const nodesSelectionVisible = computed(() => store.nodesSelectionActive)
useKeyPress(props.multiSelectionKeyCode, (keyPressed) => (store.multiSelectionActive = keyPressed))
</script>
<template>
<slot></slot>
<UserSelection v-if="userSelectionVisible" id="user-selection" />
<NodesSelection v-if="nodesSelectionVisible" id="nodes-selection" />
<UserSelection v-if="selectionKeyPresed && (store.selectionActive || store.elementsSelectable)" id="user-selection" />
<NodesSelection v-if="store.nodesSelectionActive" id="nodes-selection" />
<div class="revue-flow__pane" @click="onClick" @contextmenu="onContextMenu" @wheel="onWheel" />
</template>
+5 -4
View File
@@ -1,6 +1,6 @@
<script lang="ts" setup>
import { KeyCode, PanOnScrollMode } from '~/types'
import { useZoom, useResizeHandler, useZoomPanHelper } from '~/composables'
import { useZoom, useZoomPanHelper } from '~/composables'
import { Hooks, Store } from '~/context'
import { onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils/graph'
@@ -36,9 +36,10 @@ const hooks = inject(Hooks)!
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
const { transform } = useZoom(zoomPaneEl, props)
const { width, height } = useElementBounding(zoomPaneEl)
watch(width, (val) => (store.dimensions.width = val), { flush: 'post' })
watch(height, (val) => (store.dimensions.height = val), { flush: 'post' })
watch(transform, (val) => (store.transform = val), { flush: 'post' })
const dimensions = useResizeHandler(zoomPaneEl)
watch(dimensions, (val) => (store.dimensions = val), { flush: 'post' })
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
hooks.load.trigger({
@@ -54,6 +55,6 @@ hooks.load.trigger({
</script>
<template>
<div ref="zoom-pane" class="revue-flow__renderer revue-flow__zoompane">
<slot :transform="transform" :dimensions="dimensions"></slot>
<slot v-bind="{ transform, dimensions: { width, height } }"></slot>
</div>
</template>