chore(lint): Update eslint rules

* Remove semi
This commit is contained in:
Braks
2021-10-20 22:39:54 +02:00
parent 5ed1094dfe
commit 77eac0c12a
74 changed files with 2007 additions and 1827 deletions
+28 -28
View File
@@ -1,13 +1,13 @@
import { ref, defineComponent, CSSProperties, PropType, computed, inject, h } from 'vue';
import { ref, defineComponent, CSSProperties, PropType, computed, inject, h } from 'vue'
import { getBezierPath } from '../Edges/BezierEdge';
import { getSmoothStepPath } from '../Edges/SmoothStepEdge';
import { Node, HandleElement, Position, ConnectionLineType, ConnectionLineComponent, RevueFlowStore } from '../../types';
import { getBezierPath } from '../Edges/BezierEdge'
import { getSmoothStepPath } from '../Edges/SmoothStepEdge'
import { Node, HandleElement, Position, ConnectionLineType, ConnectionLineComponent, RevueFlowStore } from '../../types'
interface ConnectionLineProps {
connectionLineType: ConnectionLineType;
connectionLineStyle?: CSSProperties;
customConnectionLine?: ConnectionLineComponent;
connectionLineType: ConnectionLineType
connectionLineStyle?: CSSProperties
customConnectionLine?: ConnectionLineComponent
}
export default defineComponent({
@@ -29,35 +29,35 @@ export default defineComponent({
}
},
setup(props) {
const store = inject<RevueFlowStore>('store')!;
const sourceNode = ref<Node | null>(store.nodes.find((n) => n.id === store.connectionNodeId) || null);
const nodesConnectable = computed(() => store.nodesConnectable);
const store = inject<RevueFlowStore>('store')!
const sourceNode = ref<Node | null>(store.nodes.find((n) => n.id === store.connectionNodeId) || null)
const nodesConnectable = computed(() => store.nodesConnectable)
const sourceHandle = computed(() =>
store.connectionHandleId && store.connectionHandleType
? sourceNode.value?.__rf.handleBounds[store.connectionHandleType].find(
(d: HandleElement) => d.id === store.connectionHandleId
)
(d: HandleElement) => d.id === store.connectionHandleId
)
: store.connectionHandleType && sourceNode.value?.__rf.handleBounds[store.connectionHandleType][0]
);
)
const sourceHandleX = computed(() =>
sourceHandle.value ? sourceHandle.value.x + sourceHandle.value.width / 2 : (sourceNode.value?.__rf.width as number) / 2
);
)
const sourceHandleY = computed(() =>
sourceHandle.value ? sourceHandle.value.y + sourceHandle.value.height / 2 : sourceNode.value?.__rf.height
);
const sourceX = computed(() => sourceNode.value?.__rf.position.x + sourceHandleX.value);
const sourceY = computed(() => sourceNode.value?.__rf.position.y + sourceHandleY.value);
)
const sourceX = computed(() => sourceNode.value?.__rf.position.x + sourceHandleX.value)
const sourceY = computed(() => sourceNode.value?.__rf.position.y + sourceHandleY.value)
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2]);
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2]);
const targetX = computed(() => (store.connectionPosition.x - store.transform[0]) / store.transform[2])
const targetY = computed(() => (store.connectionPosition.y - store.transform[1]) / store.transform[2])
const isRightOrLeft = computed(
() => sourceHandle.value?.position === Position.Left || sourceHandle.value?.position === Position.Right
);
const targetPosition = computed(() => (isRightOrLeft.value ? Position.Left : Position.Top));
)
const targetPosition = computed(() => (isRightOrLeft.value ? Position.Left : Position.Top))
let dAttr = computed(() => `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`);
let dAttr = computed(() => `M${sourceX.value},${sourceY.value} ${targetX.value},${targetY.value}`)
if (props.connectionLineType === ConnectionLineType.Bezier) {
dAttr = computed(() =>
@@ -69,7 +69,7 @@ export default defineComponent({
targetY: targetY.value,
targetPosition: targetPosition.value
})
);
)
} else if (props.connectionLineType === ConnectionLineType.Step) {
dAttr = computed(() =>
getSmoothStepPath({
@@ -81,7 +81,7 @@ export default defineComponent({
targetPosition: targetPosition.value,
borderRadius: 0
})
);
)
} else if (props.connectionLineType === ConnectionLineType.SmoothStep) {
dAttr = computed(() =>
getSmoothStepPath({
@@ -92,7 +92,7 @@ export default defineComponent({
targetY: targetY.value,
targetPosition: targetPosition.value
})
);
)
}
if (props.customConnectionLine) {
@@ -110,7 +110,7 @@ export default defineComponent({
connectionLineStyle: props.connectionLineStyle
})}
</g>
);
)
}
return () =>
@@ -120,6 +120,6 @@ export default defineComponent({
</g>
) : (
''
);
)
}
});
})
+29 -29
View File
@@ -1,18 +1,18 @@
import { defineComponent } from 'vue';
import EdgeText from './EdgeText';
import { getMarkerEnd, getCenter, GetCenterParams, DefaultEdgeProps } from './utils';
import { ArrowHeadType, EdgeType, Position } from '../../types';
import { reactify } from '@vueuse/core';
import { defineComponent } from 'vue'
import EdgeText from './EdgeText'
import { getMarkerEnd, getCenter, GetCenterParams, DefaultEdgeProps } from './utils'
import { ArrowHeadType, EdgeType, Position } from '../../types'
import { reactify } from '@vueuse/core'
interface GetBezierPathParams {
sourceX: number;
sourceY: number;
sourcePosition?: Position;
targetX: number;
targetY: number;
targetPosition?: Position;
centerX?: number;
centerY?: number;
sourceX: number
sourceY: number
sourcePosition?: Position
targetX: number
targetY: number
targetPosition?: Position
centerX?: number
centerY?: number
}
export function getBezierPath({
@@ -25,23 +25,23 @@ export function getBezierPath({
centerX,
centerY
}: GetBezierPathParams): string {
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY });
const leftAndRight = [Position.Left, Position.Right];
const [_centerX, _centerY] = getCenter({ sourceX, sourceY, targetX, targetY })
const leftAndRight = [Position.Left, Position.Right]
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
const cX = typeof centerX !== 'undefined' ? centerX : _centerX
const cY = typeof centerY !== 'undefined' ? centerY : _centerY
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`;
let path = `M${sourceX},${sourceY} C${sourceX},${cY} ${targetX},${cY} ${targetX},${targetY}`
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`;
path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`
} else if (leftAndRight.includes(targetPosition)) {
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`;
path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`
} else if (leftAndRight.includes(sourcePosition)) {
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`;
path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`
}
return path;
return path
}
export default defineComponent({
@@ -58,8 +58,8 @@ export default defineComponent({
targetY: targetY,
sourcePosition: sourcePosition,
targetPosition: targetPosition
});
});
})
})
const path = reactify(({ sourceX, sourceY, targetX, targetY, targetPosition, sourcePosition }: GetBezierPathParams) => {
return getBezierPath({
sourceX: sourceX,
@@ -68,10 +68,10 @@ export default defineComponent({
targetY: targetY,
targetPosition: targetPosition,
sourcePosition: sourcePosition
});
});
})
})
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
return () => (
<>
@@ -94,6 +94,6 @@ export default defineComponent({
/>
) : null}
</>
);
)
}
}) as EdgeType;
}) as EdgeType
+69 -69
View File
@@ -1,24 +1,24 @@
import { computed, defineComponent, h, inject, PropType, ref, watchPostEffect } from 'vue';
import EdgeAnchor from './EdgeAnchor';
import { ConnectionMode, Edge, Elements, Node, Position, RevueFlowStore, Transform } from '../../types';
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../container/EdgeRenderer/utils';
import { isEdge } from '../../utils/graph';
import { onMouseDown } from '../Handle/handler';
import { controlledRef } from '@vueuse/core';
import { computed, defineComponent, h, inject, PropType, ref, watchPostEffect } from 'vue'
import EdgeAnchor from './EdgeAnchor'
import { ConnectionMode, Edge, Elements, Node, Position, RevueFlowStore, Transform } from '../../types'
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
import { getEdgePositions, getHandle, getSourceTargetNodes, isEdgeVisible } from '../../container/EdgeRenderer/utils'
import { isEdge } from '../../utils/graph'
import { onMouseDown } from '../Handle/handler'
import { controlledRef } from '@vueuse/core'
interface EdgeProps {
edge: Edge;
nodes: Node[];
selectedElements: Elements | null;
elementsSelectable: boolean;
transform: Transform;
width: number;
height: number;
onlyRenderVisibleElements: boolean;
connectionMode?: ConnectionMode;
markerEndId?: string;
edgeUpdaterRadius?: number;
edge: Edge
nodes: Node[]
selectedElements: Elements | null
elementsSelectable: boolean
transform: Transform
width: number
height: number
onlyRenderVisibleElements: boolean
connectionMode?: ConnectionMode
markerEndId?: string
edgeUpdaterRadius?: number
}
export default defineComponent({
@@ -54,41 +54,41 @@ export default defineComponent({
}
},
setup(props) {
const store = inject<RevueFlowStore>('store')!;
const hooks = inject<RevueFlowHooks>('hooks')!;
const store = inject<RevueFlowStore>('store')!
const hooks = inject<RevueFlowHooks>('hooks')!
const nodes = controlledRef(getSourceTargetNodes(props.edge, store.nodes), {
onBeforeChange: (value, oldValue) => {
if (JSON.stringify(value) === JSON.stringify(oldValue)) return false;
if (JSON.stringify(value) === JSON.stringify(oldValue)) return false
}
});
})
watchPostEffect(() => {
nodes.value = getSourceTargetNodes(props.edge, store.nodes);
});
nodes.value = getSourceTargetNodes(props.edge, store.nodes)
})
hooks.connect.on((connection) => {
hooks.edgeUpdate.trigger({ edge: props.edge, connection });
});
hooks.edgeUpdate.trigger({ edge: props.edge, connection })
})
if (!nodes.value.sourceNode) {
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`);
console.warn(`couldn't create edge for source id: ${props.edge.source}; edge id: ${props.edge.id}`)
}
if (!nodes.value.targetNode) {
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`);
console.warn(`couldn't create edge for target id: ${props.edge.target}; edge id: ${props.edge.id}`)
}
// when connection type is loose we can define all handles as sources
const targetNodeHandles =
props.connectionMode === ConnectionMode.Strict
? nodes.value.targetNode?.__rf.handleBounds.target
: nodes.value.targetNode?.__rf.handleBounds.target || nodes.value.targetNode?.__rf.handleBounds.source;
: nodes.value.targetNode?.__rf.handleBounds.target || nodes.value.targetNode?.__rf.handleBounds.source
const sourceHandle =
nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null);
const targetHandle = getHandle(targetNodeHandles, props.edge.targetHandle || null);
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom;
const targetPosition = targetHandle ? targetHandle.position : Position.Top;
nodes.value.sourceNode && getHandle(nodes.value.sourceNode.__rf.handleBounds.source, props.edge.sourceHandle || null)
const targetHandle = getHandle(targetNodeHandles, props.edge.targetHandle || null)
const sourcePosition = sourceHandle ? sourceHandle.position : Position.Bottom
const targetPosition = targetHandle ? targetHandle.position : Position.Top
const isVisible = ({ sourceX, sourceY, targetX, targetY }: Record<string, number>) => {
return props.onlyRenderVisibleElements
@@ -99,10 +99,10 @@ export default defineComponent({
height: store.height || 0,
transform: store.transform
})
: true;
};
: true
}
const isSelected = computed(() => store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false);
const isSelected = computed(() => store.selectedElements?.some((elm) => isEdge(elm) && elm.id === props.edge.id) || false)
const edgeElement = () => {
const el: Edge = {
@@ -110,51 +110,51 @@ export default defineComponent({
source: props.edge.source,
target: props.edge.target,
type: props.edge.type
};
}
if (props.edge.sourceHandle) {
el.sourceHandle = props.edge.sourceHandle;
el.sourceHandle = props.edge.sourceHandle
}
if (props.edge.targetHandle) {
el.targetHandle = props.edge.targetHandle;
el.targetHandle = props.edge.targetHandle
}
if (typeof props.edge.data !== 'undefined') {
el.data = props.edge.data;
el.data = props.edge.data
}
return el;
};
return el
}
const onEdgeClick = (event: MouseEvent) => {
if (store.elementsSelectable) {
store.unsetNodesSelection();
store.addSelectedElements(edgeElement() as any);
store.unsetNodesSelection()
store.addSelectedElements(edgeElement() as any)
}
hooks.edgeClick.trigger({ event, edge: edgeElement() });
};
hooks.edgeClick.trigger({ event, edge: edgeElement() })
}
const onEdgeContextMenu = (event: MouseEvent) =>
hooks.edgeContextMenu.trigger({
event,
edge: edgeElement()
});
})
const onEdgeMouseEnter = (event: MouseEvent) => hooks.edgeMouseEnter.trigger({ event, edge: edgeElement() });
const onEdgeMouseEnter = (event: MouseEvent) => hooks.edgeMouseEnter.trigger({ event, edge: edgeElement() })
const onEdgeMouseMove = (event: MouseEvent) => hooks.edgeMouseMove.trigger({ event, edge: edgeElement() });
const onEdgeMouseMove = (event: MouseEvent) => hooks.edgeMouseMove.trigger({ event, edge: edgeElement() })
const onEdgeMouseLeave = (event: MouseEvent) => hooks.edgeMouseLeave.trigger({ event, edge: edgeElement() });
const onEdgeMouseLeave = (event: MouseEvent) => hooks.edgeMouseLeave.trigger({ event, edge: edgeElement() })
const handleEdgeUpdater = (event: MouseEvent, isSourceHandle: boolean) => {
const nodeId = isSourceHandle ? props.edge.target : props.edge.source;
const handleId = isSourceHandle ? props.edge.targetHandle : props.edge.sourceHandle;
const isValidConnection = () => true;
const isTarget = isSourceHandle;
const nodeId = isSourceHandle ? props.edge.target : props.edge.source
const handleId = isSourceHandle ? props.edge.targetHandle : props.edge.sourceHandle
const isValidConnection = () => true
const isTarget = isSourceHandle
hooks.edgeUpdateStart.trigger({ event, edge: edgeElement() });
hooks.edgeUpdateStart.trigger({ event, edge: edgeElement() })
onMouseDown(
event,
store,
@@ -164,20 +164,20 @@ export default defineComponent({
isTarget,
isValidConnection,
isSourceHandle ? 'target' : 'source'
);
};
)
}
const onEdgeUpdaterSourceMouseDown = (event: MouseEvent) => {
handleEdgeUpdater(event, true);
};
handleEdgeUpdater(event, true)
}
const onEdgeUpdaterTargetMouseDown = (event: MouseEvent) => {
handleEdgeUpdater(event, false);
};
handleEdgeUpdater(event, false)
}
const updating = ref<boolean>(false);
const onEdgeUpdaterMouseEnter = () => (updating.value = true);
const onEdgeUpdaterMouseOut = () => (updating.value = false);
const updating = ref<boolean>(false)
const onEdgeUpdaterMouseEnter = () => (updating.value = true)
const onEdgeUpdaterMouseOut = () => (updating.value = false)
return () => {
const { targetX, targetY, sourceX, sourceY } = getEdgePositions(
@@ -187,7 +187,7 @@ export default defineComponent({
nodes.value.targetNode as Node,
targetHandle,
targetPosition
);
)
return !props.edge.isHidden && isVisible({ targetX, targetY, sourceX, sourceY }) ? (
<g
class={[
@@ -242,7 +242,7 @@ export default defineComponent({
</g>
) : (
''
);
};
)
}
}
});
})
+16 -16
View File
@@ -1,23 +1,23 @@
import { Position } from '../../types';
import { defineComponent, HTMLAttributes, PropType } from 'vue';
import { Position } from '../../types'
import { defineComponent, HTMLAttributes, PropType } from 'vue'
const shiftX = (x: number, shift: number, position: Position): number => {
if (position === Position.Left) return x - shift;
if (position === Position.Right) return x + shift;
return x;
};
if (position === Position.Left) return x - shift
if (position === Position.Right) return x + shift
return x
}
const shiftY = (y: number, shift: number, position: Position): number => {
if (position === Position.Top) return y - shift;
if (position === Position.Bottom) return y + shift;
return y;
};
if (position === Position.Top) return y - shift
if (position === Position.Bottom) return y + shift
return y
}
export interface EdgeAnchorProps extends HTMLAttributes {
position: Position;
centerX: number;
centerY: number;
radius?: number;
position: Position
centerX: number
centerY: number
radius?: number
}
export default defineComponent({
@@ -50,6 +50,6 @@ export default defineComponent({
stroke="transparent"
fill="transparent"
/>
);
)
}
});
})
+9 -9
View File
@@ -1,5 +1,5 @@
import { EdgeTextProps, Rect } from '../../types';
import { defineComponent, PropType, ref, watchEffect } from 'vue';
import { EdgeTextProps, Rect } from '../../types'
import { defineComponent, PropType, ref, watchEffect } from 'vue'
export default defineComponent({
props: {
@@ -37,11 +37,11 @@ export default defineComponent({
}
},
setup(props, { slots }) {
const edgeRef = ref<SVGTextElement | null>(null);
const edgeTextBox = ref<Rect>({ x: 0, y: 0, width: 0, height: 0 });
const edgeRef = ref<SVGTextElement | null>(null)
const edgeTextBox = ref<Rect>({ x: 0, y: 0, width: 0, height: 0 })
watchEffect(() => {
const textBbox = edgeRef.value?.getBBox();
const textBbox = edgeRef.value?.getBBox()
if (textBbox) {
edgeTextBox.value = {
@@ -49,9 +49,9 @@ export default defineComponent({
y: textBbox.y,
width: textBbox.width,
height: textBbox.height
};
}
}
});
})
return () => (
<g
@@ -75,6 +75,6 @@ export default defineComponent({
</text>
{slots.default ? slots.default() : ''}
</g>
);
)
}
});
})
+54 -55
View File
@@ -1,33 +1,33 @@
import { defineComponent } from 'vue';
import EdgeText from './EdgeText';
import { getMarkerEnd, getCenter, EdgeSmoothProps, GetCenterParams } from './utils';
import { ArrowHeadType, EdgeType, Position } from '../../types';
import { reactify } from '@vueuse/core';
import { getBezierPath } from './BezierEdge';
import { defineComponent } from 'vue'
import EdgeText from './EdgeText'
import { getMarkerEnd, getCenter, EdgeSmoothProps, GetCenterParams } from './utils'
import { ArrowHeadType, EdgeType, Position } from '../../types'
import { reactify } from '@vueuse/core'
import { getBezierPath } from './BezierEdge'
// These are some helper methods for drawing the round corners
// The name indicates the direction of the path. "bottomLeftCorner" goes
// from bottom to the left and "leftBottomCorner" goes from left to the bottom.
// We have to consider the direction of the paths because of the animated lines.
const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}`;
const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}`;
const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}`;
const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}`;
const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}`;
const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}`;
const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`;
const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`;
const bottomLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x + size},${y}`
const leftBottomCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y - size}`
const bottomRightCorner = (x: number, y: number, size: number): string => `L ${x},${y - size}Q ${x},${y} ${x - size},${y}`
const rightBottomCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y - size}`
const leftTopCorner = (x: number, y: number, size: number): string => `L ${x + size},${y}Q ${x},${y} ${x},${y + size}`
const topLeftCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x + size},${y}`
const topRightCorner = (x: number, y: number, size: number): string => `L ${x},${y + size}Q ${x},${y} ${x - size},${y}`
const rightTopCorner = (x: number, y: number, size: number): string => `L ${x - size},${y}Q ${x},${y} ${x},${y + size}`
interface GetSmoothStepPathParams {
sourceX: number;
sourceY: number;
sourcePosition?: Position;
targetX: number;
targetY: number;
targetPosition?: Position;
borderRadius?: number;
centerX?: number;
centerY?: number;
sourceX: number
sourceY: number
sourcePosition?: Position
targetX: number
targetY: number
targetPosition?: Position
borderRadius?: number
centerX?: number
centerY?: number
}
export function getSmoothStepPath({
@@ -41,56 +41,55 @@ export function getSmoothStepPath({
centerX,
centerY
}: GetSmoothStepPathParams): string {
const [_centerX, _centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY });
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX));
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY));
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY);
const leftAndRight = [Position.Left, Position.Right];
const cX = typeof centerX !== 'undefined' ? centerX : _centerX;
const cY = typeof centerY !== 'undefined' ? centerY : _centerY;
const [_centerX, _centerY, offsetX, offsetY] = getCenter({ sourceX, sourceY, targetX, targetY })
const cornerWidth = Math.min(borderRadius, Math.abs(targetX - sourceX))
const cornerHeight = Math.min(borderRadius, Math.abs(targetY - sourceY))
const cornerSize = Math.min(cornerWidth, cornerHeight, offsetX, offsetY)
const leftAndRight = [Position.Left, Position.Right]
const cX = typeof centerX !== 'undefined' ? centerX : _centerX
const cY = typeof centerY !== 'undefined' ? centerY : _centerY
let firstCornerPath;
let secondCornerPath;
let firstCornerPath
let secondCornerPath
if (sourceX <= targetX) {
firstCornerPath = sourceY <= targetY ? bottomLeftCorner(sourceX, cY, cornerSize) : topLeftCorner(sourceX, cY, cornerSize);
secondCornerPath = sourceY <= targetY ? rightTopCorner(targetX, cY, cornerSize) : rightBottomCorner(targetX, cY, cornerSize);
firstCornerPath = sourceY <= targetY ? bottomLeftCorner(sourceX, cY, cornerSize) : topLeftCorner(sourceX, cY, cornerSize)
secondCornerPath = sourceY <= targetY ? rightTopCorner(targetX, cY, cornerSize) : rightBottomCorner(targetX, cY, cornerSize)
} else {
firstCornerPath = sourceY < targetY ? bottomRightCorner(sourceX, cY, cornerSize) : topRightCorner(sourceX, cY, cornerSize);
secondCornerPath = sourceY < targetY ? leftTopCorner(targetX, cY, cornerSize) : leftBottomCorner(targetX, cY, cornerSize);
firstCornerPath = sourceY < targetY ? bottomRightCorner(sourceX, cY, cornerSize) : topRightCorner(sourceX, cY, cornerSize)
secondCornerPath = sourceY < targetY ? leftTopCorner(targetX, cY, cornerSize) : leftBottomCorner(targetX, cY, cornerSize)
}
if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
if (sourceX <= targetX) {
firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize);
secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize);
firstCornerPath = sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize)
secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize)
} else if (sourcePosition === Position.Right && targetPosition === Position.Left) {
// and sourceX > targetX
firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize);
secondCornerPath =
sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize);
firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize)
secondCornerPath = sourceY <= targetY ? bottomRightCorner(cX, targetY, cornerSize) : topRightCorner(cX, targetY, cornerSize)
}
} else if (leftAndRight.includes(sourcePosition) && !leftAndRight.includes(targetPosition)) {
if (sourceX <= targetX) {
firstCornerPath =
sourceY <= targetY ? rightTopCorner(targetX, sourceY, cornerSize) : rightBottomCorner(targetX, sourceY, cornerSize);
sourceY <= targetY ? rightTopCorner(targetX, sourceY, cornerSize) : rightBottomCorner(targetX, sourceY, cornerSize)
} else {
firstCornerPath =
sourceY <= targetY ? leftTopCorner(targetX, sourceY, cornerSize) : leftBottomCorner(targetX, sourceY, cornerSize);
sourceY <= targetY ? leftTopCorner(targetX, sourceY, cornerSize) : leftBottomCorner(targetX, sourceY, cornerSize)
}
secondCornerPath = '';
secondCornerPath = ''
} else if (!leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) {
if (sourceX <= targetX) {
firstCornerPath =
sourceY <= targetY ? bottomLeftCorner(sourceX, targetY, cornerSize) : topLeftCorner(sourceX, targetY, cornerSize);
sourceY <= targetY ? bottomLeftCorner(sourceX, targetY, cornerSize) : topLeftCorner(sourceX, targetY, cornerSize)
} else {
firstCornerPath =
sourceY <= targetY ? bottomRightCorner(sourceX, targetY, cornerSize) : topRightCorner(sourceX, targetY, cornerSize);
sourceY <= targetY ? bottomRightCorner(sourceX, targetY, cornerSize) : topRightCorner(sourceX, targetY, cornerSize)
}
secondCornerPath = '';
secondCornerPath = ''
}
return `M ${sourceX},${sourceY}${firstCornerPath}${secondCornerPath}L ${targetX},${targetY}`;
return `M ${sourceX},${sourceY}${firstCornerPath}${secondCornerPath}L ${targetX},${targetY}`
}
export default defineComponent({
@@ -107,8 +106,8 @@ export default defineComponent({
targetY: targetY,
sourcePosition: sourcePosition,
targetPosition: targetPosition
});
});
})
})
const path = reactify(({ sourceX, sourceY, targetX, targetY, targetPosition, sourcePosition }: GetSmoothStepPathParams) => {
return getBezierPath({
sourceX: sourceX,
@@ -117,10 +116,10 @@ export default defineComponent({
targetY: targetY,
targetPosition: targetPosition,
sourcePosition: sourcePosition
});
});
})
})
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
return () => (
<>
@@ -143,6 +142,6 @@ export default defineComponent({
/>
) : null}
</>
);
)
}
}) as unknown as EdgeType;
}) as unknown as EdgeType
+6 -6
View File
@@ -1,7 +1,7 @@
import { defineComponent } from 'vue';
import SmoothStepEdge from './SmoothStepEdge';
import { EdgeSmoothProps } from './utils';
import { EdgeType } from '../../types';
import { defineComponent } from 'vue'
import SmoothStepEdge from './SmoothStepEdge'
import { EdgeSmoothProps } from './utils'
import { EdgeType } from '../../types'
export default defineComponent({
components: { SmoothStepEdge },
@@ -10,6 +10,6 @@ export default defineComponent({
...EdgeSmoothProps
},
setup(props) {
return () => <SmoothStepEdge {...props} borderRadius={0} />;
return () => <SmoothStepEdge {...props} borderRadius={0} />
}
}) as EdgeType;
}) as EdgeType
+14 -14
View File
@@ -1,8 +1,8 @@
import { defineComponent } from 'vue';
import EdgeText from './EdgeText';
import { getMarkerEnd, DefaultEdgeProps } from './utils';
import { reactify } from '@vueuse/core';
import { ArrowHeadType, EdgeType } from '../../types';
import { defineComponent } from 'vue'
import EdgeText from './EdgeText'
import { getMarkerEnd, DefaultEdgeProps } from './utils'
import { reactify } from '@vueuse/core'
import { ArrowHeadType, EdgeType } from '../../types'
export default defineComponent({
inheritAttrs: false,
@@ -11,15 +11,15 @@ export default defineComponent({
},
setup(props) {
const centerY = reactify((targetY: number, sourceY: number) => {
const yOffset = Math.abs(targetY - sourceY) / 2;
return targetY < sourceY ? targetY + yOffset : targetY - yOffset;
});
const yOffset = Math.abs(targetY - sourceY) / 2
return targetY < sourceY ? targetY + yOffset : targetY - yOffset
})
const centerX = reactify((targetX: number, sourceX: number) => {
const xOffset = Math.abs(targetX - sourceX) / 2;
return targetX < sourceX ? targetX + xOffset : targetX - xOffset;
});
const xOffset = Math.abs(targetX - sourceX) / 2
return targetX < sourceX ? targetX + xOffset : targetX - xOffset
})
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId));
const markerEnd = reactify((arrowHeadType?: ArrowHeadType, markerEndId?: string) => getMarkerEnd(arrowHeadType, markerEndId))
return () => (
<>
@@ -42,6 +42,6 @@ export default defineComponent({
/>
) : null}
</>
);
)
}
}) as unknown as EdgeType;
}) as unknown as EdgeType
+4 -4
View File
@@ -1,4 +1,4 @@
export { default as BezierEdge } from './BezierEdge';
export { default as StepEdge } from './StepEdge';
export { default as SmoothStepEdge } from './SmoothStepEdge';
export { default as StraightEdge } from './StraightEdge';
export { default as BezierEdge } from './BezierEdge'
export { default as StepEdge } from './StepEdge'
export { default as SmoothStepEdge } from './SmoothStepEdge'
export { default as StraightEdge } from './StraightEdge'
+30 -30
View File
@@ -1,24 +1,24 @@
import { ArrowHeadType, Position, EdgeProps, EdgeSmoothStepProps } from '../../types';
import { PropType } from 'vue';
import { ArrowHeadType, Position, EdgeProps, EdgeSmoothStepProps } from '../../types'
import { PropType } from 'vue'
export const getMarkerEnd = (arrowHeadType?: ArrowHeadType, markerEndId?: string): string => {
if (typeof markerEndId !== 'undefined' && markerEndId) {
return `url(#${markerEndId})`;
return `url(#${markerEndId})`
}
return typeof arrowHeadType !== 'undefined' ? `url(#revue-flow__${arrowHeadType})` : 'none';
};
export interface GetCenterParams {
sourceX: number;
sourceY: number;
targetX: number;
targetY: number;
sourcePosition?: Position;
targetPosition?: Position;
return typeof arrowHeadType !== 'undefined' ? `url(#revue-flow__${arrowHeadType})` : 'none'
}
const LeftOrRight = [Position.Left, Position.Right];
export interface GetCenterParams {
sourceX: number
sourceY: number
targetX: number
targetY: number
sourcePosition?: Position
targetPosition?: Position
}
const LeftOrRight = [Position.Left, Position.Right]
export const getCenter = ({
sourceX,
@@ -28,31 +28,31 @@ export const getCenter = ({
sourcePosition = Position.Bottom,
targetPosition = Position.Top
}: GetCenterParams): [number, number, number, number] => {
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition);
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition);
const sourceIsLeftOrRight = LeftOrRight.includes(sourcePosition)
const targetIsLeftOrRight = LeftOrRight.includes(targetPosition)
// we expect flows to be horizontal or vertical (all handles left or right respectively top or bottom)
// a mixed edge is when one the source is on the left and the target is on the top for example.
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight);
const mixedEdge = (sourceIsLeftOrRight && !targetIsLeftOrRight) || (targetIsLeftOrRight && !sourceIsLeftOrRight)
if (mixedEdge) {
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0;
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset;
const xOffset = sourceIsLeftOrRight ? Math.abs(targetX - sourceX) : 0
const centerX = sourceX > targetX ? sourceX - xOffset : sourceX + xOffset
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY);
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset;
const yOffset = sourceIsLeftOrRight ? 0 : Math.abs(targetY - sourceY)
const centerY = sourceY < targetY ? sourceY + yOffset : sourceY - yOffset
return [centerX, centerY, xOffset, yOffset];
return [centerX, centerY, xOffset, yOffset]
}
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const xOffset = Math.abs(targetX - sourceX) / 2
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset
const yOffset = Math.abs(targetY - sourceY) / 2;
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset;
const yOffset = Math.abs(targetY - sourceY) / 2
const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset
return [centerX, centerY, xOffset, yOffset];
};
return [centerX, centerY, xOffset, yOffset]
}
export const DefaultEdgeProps = {
id: {
@@ -165,7 +165,7 @@ export const DefaultEdgeProps = {
required: false,
default: undefined
}
};
}
export const EdgeSmoothProps = {
...DefaultEdgeProps,
@@ -174,4 +174,4 @@ export const EdgeSmoothProps = {
required: false,
default: 5
}
};
}
+61 -61
View File
@@ -1,15 +1,15 @@
import { getHostForElement } from '../../utils';
import { ElementId, ConnectionMode, Connection, HandleType, RevueFlowStore } from '../../types';
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
import { getHostForElement } from '../../utils'
import { ElementId, ConnectionMode, Connection, HandleType, RevueFlowStore } from '../../types'
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
export type ValidConnectionFunc = (connection: Connection) => boolean;
export type ValidConnectionFunc = (connection: Connection) => boolean
type Result = {
elementBelow: Element | null;
isValid: boolean;
connection: Connection;
isHoveringHandle: boolean;
};
elementBelow: Element | null
isValid: boolean
connection: Connection
isHoveringHandle: boolean
}
// checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 }
function checkElementBelowIsValid(
@@ -21,27 +21,27 @@ function checkElementBelowIsValid(
isValidConnection: ValidConnectionFunc,
doc: Document | ShadowRoot
) {
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY);
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false;
const elementBelowIsSource = elementBelow?.classList.contains('source') || false;
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
const elementBelowIsTarget = elementBelow?.classList.contains('target') || false
const elementBelowIsSource = elementBelow?.classList.contains('source') || false
const result: Result = {
elementBelow,
isValid: false,
connection: { source: null, target: null, sourceHandle: null, targetHandle: null },
isHoveringHandle: false
};
}
if (elementBelow && (elementBelowIsTarget || elementBelowIsSource)) {
result.isHoveringHandle = true;
result.isHoveringHandle = true
// in strict mode we don't allow target to target or source to source connections
const isValid =
connectionMode === ConnectionMode.Strict ? (isTarget && elementBelowIsSource) || (!isTarget && elementBelowIsTarget) : true;
connectionMode === ConnectionMode.Strict ? (isTarget && elementBelowIsSource) || (!isTarget && elementBelowIsTarget) : true
if (isValid) {
const elementBelowNodeId = elementBelow.getAttribute('data-nodeid');
const elementBelowHandleId = elementBelow.getAttribute('data-handleid');
const elementBelowNodeId = elementBelow.getAttribute('data-nodeid')
const elementBelowHandleId = elementBelow.getAttribute('data-handleid')
const connection: Connection = isTarget
? {
source: elementBelowNodeId,
@@ -54,30 +54,30 @@ function checkElementBelowIsValid(
sourceHandle: handleId,
target: elementBelowNodeId,
targetHandle: elementBelowHandleId
};
}
result.connection = connection;
result.isValid = isValidConnection(connection);
result.connection = connection
result.isValid = isValidConnection(connection)
}
}
return result;
return result
}
function resetRecentHandle(hoveredHandle: Element): void {
hoveredHandle?.classList.remove('revue-flow__handle-valid');
hoveredHandle?.classList.remove('revue-flow__handle-connecting');
hoveredHandle?.classList.remove('revue-flow__handle-valid')
hoveredHandle?.classList.remove('revue-flow__handle-connecting')
}
export function onMouseDown(
event: MouseEvent,
store: RevueFlowStore,
hooks: {
connectStart: RevueFlowHooks['connectStart'];
connectStop: RevueFlowHooks['connectStop'];
connectEnd: RevueFlowHooks['connectEnd'];
connect: RevueFlowHooks['connect'];
edgeUpdateEnd: RevueFlowHooks['edgeUpdateEnd'];
connectStart: RevueFlowHooks['connectStart']
connectStop: RevueFlowHooks['connectStop']
connectEnd: RevueFlowHooks['connectEnd']
connect: RevueFlowHooks['connect']
edgeUpdateEnd: RevueFlowHooks['edgeUpdateEnd']
},
handleId: ElementId | null,
nodeId: ElementId,
@@ -85,39 +85,39 @@ export function onMouseDown(
isValidConnection: ValidConnectionFunc,
elementEdgeUpdaterType?: HandleType
): void {
const revueFlowNode = (event.target as Element).closest('.revue-flow');
const revueFlowNode = (event.target as Element).closest('.revue-flow')
// when revue-flow is used inside a shadow root we can't use document
const doc = getHostForElement(event.target as HTMLElement);
const doc = getHostForElement(event.target as HTMLElement)
if (!doc) {
return;
return
}
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY);
const elementBelowIsTarget = elementBelow?.classList.contains('target');
const elementBelowIsSource = elementBelow?.classList.contains('source');
const elementBelow = doc.elementFromPoint(event.clientX, event.clientY)
const elementBelowIsTarget = elementBelow?.classList.contains('target')
const elementBelowIsSource = elementBelow?.classList.contains('source')
if (!revueFlowNode || (!elementBelowIsTarget && !elementBelowIsSource && !elementEdgeUpdaterType)) {
return;
return
}
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source';
const containerBounds = revueFlowNode.getBoundingClientRect();
let recentHoveredHandle: Element;
const handleType = elementEdgeUpdaterType ? elementEdgeUpdaterType : elementBelowIsTarget ? 'target' : 'source'
const containerBounds = revueFlowNode.getBoundingClientRect()
let recentHoveredHandle: Element
store.connectionPosition.x = event.clientX - containerBounds.left;
store.connectionPosition.y = event.clientY - containerBounds.top;
store.connectionPosition.x = event.clientX - containerBounds.left
store.connectionPosition.y = event.clientY - containerBounds.top
store.setConnectionNodeId({
connectionNodeId: nodeId,
connectionHandleId: handleId,
connectionHandleType: handleType
});
hooks.connectStart.trigger({ event, params: { nodeId, handleId, handleType } });
})
hooks.connectStart.trigger({ event, params: { nodeId, handleId, handleType } })
function onMouseMove(event: MouseEvent) {
store.connectionPosition.x = event.clientX - containerBounds.left;
store.connectionPosition.y = event.clientY - containerBounds.top;
store.connectionPosition.x = event.clientX - containerBounds.left
store.connectionPosition.y = event.clientY - containerBounds.top
const { connection, elementBelow, isValid, isHoveringHandle } = checkElementBelowIsValid(
event,
@@ -127,18 +127,18 @@ export function onMouseDown(
handleId,
isValidConnection,
doc
);
)
if (!isHoveringHandle) {
return resetRecentHandle(recentHoveredHandle);
return resetRecentHandle(recentHoveredHandle)
}
const isOwnHandle = connection.source === connection.target;
const isOwnHandle = connection.source === connection.target
if (!isOwnHandle && elementBelow) {
recentHoveredHandle = elementBelow;
elementBelow.classList.add('revue-flow__handle-connecting');
elementBelow.classList.toggle('revue-flow__handle-valid', isValid);
recentHoveredHandle = elementBelow
elementBelow.classList.add('revue-flow__handle-connecting')
elementBelow.classList.toggle('revue-flow__handle-valid', isValid)
}
}
@@ -151,27 +151,27 @@ export function onMouseDown(
handleId,
isValidConnection,
doc
);
)
hooks.connectStop.trigger(event);
hooks.connectStop.trigger(event)
if (isValid) {
hooks.connect.trigger(connection);
hooks.connect.trigger(connection)
}
hooks.connectEnd.trigger(event);
hooks.connectEnd.trigger(event)
if (elementEdgeUpdaterType) {
hooks.edgeUpdateEnd.trigger({ event } as any);
hooks.edgeUpdateEnd.trigger({ event } as any)
}
resetRecentHandle(recentHoveredHandle);
store.setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null });
resetRecentHandle(recentHoveredHandle)
store.setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null })
doc.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject);
doc.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject);
doc.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject)
doc.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject)
}
doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject);
doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject);
doc.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject)
doc.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject)
}
+11 -11
View File
@@ -1,9 +1,9 @@
import { ElementId, Position, RevueFlowStore } from '../../types';
import { onMouseDown, ValidConnectionFunc } from './handler';
import { defineComponent, inject, PropType } from 'vue';
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
import { ElementId, Position, RevueFlowStore } from '../../types'
import { onMouseDown, ValidConnectionFunc } from './handler'
import { defineComponent, inject, PropType } from 'vue'
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
const alwaysValid = () => true;
const alwaysValid = () => true
export default defineComponent({
props: {
@@ -34,12 +34,12 @@ export default defineComponent({
}
},
setup(props, { slots }) {
const store = inject<RevueFlowStore>('store')!;
const hooks = inject<RevueFlowHooks>('hooks')!;
const nodeId = inject<ElementId>('NodeIdContext')!;
const store = inject<RevueFlowStore>('store')!
const hooks = inject<RevueFlowHooks>('hooks')!
const nodeId = inject<ElementId>('NodeIdContext')!
const onMouseDownHandler = (event: MouseEvent) =>
onMouseDown(event, store, hooks, props.id as string, nodeId, props.type === 'target', props.isValidConnection);
onMouseDown(event, store, hooks, props.id as string, nodeId, props.type === 'target', props.isValidConnection)
return () => (
<div
@@ -60,6 +60,6 @@ export default defineComponent({
>
{slots.default ? slots.default() : ''}
</div>
);
)
}
});
})
+5 -5
View File
@@ -1,6 +1,6 @@
import { defineComponent, PropType } from 'vue';
import Handle from '../../components/Handle';
import { NodeProps, NodeType, Position } from '../../types';
import { defineComponent, PropType } from 'vue'
import Handle from '../../components/Handle'
import { NodeProps, NodeType, Position } from '../../types'
export default defineComponent({
name: 'DefaultNode',
@@ -35,6 +35,6 @@ export default defineComponent({
{props.data?.label}
<Handle type="source" position={props.sourcePosition} isConnectable={props.isConnectable} />
</>
);
)
}
}) as NodeType;
}) as NodeType
+5 -5
View File
@@ -1,6 +1,6 @@
import Handle from '../../components/Handle';
import { NodeProps, NodeType, Position } from '../../types';
import { defineComponent, PropType } from 'vue';
import Handle from '../../components/Handle'
import { NodeProps, NodeType, Position } from '../../types'
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'InputNode',
@@ -29,6 +29,6 @@ export default defineComponent({
{props.data?.label}
<Handle type="source" position={props.sourcePosition} isConnectable={props.isConnectable} />
</>
);
)
}
}) as NodeType;
}) as NodeType
+61 -61
View File
@@ -1,14 +1,14 @@
import { computed, defineComponent, h, inject, onMounted, PropType, provide } from 'vue';
import { templateRef, useResizeObserver } from '@vueuse/core';
import { DraggableCore, DraggableEventListener } from '@braks/revue-draggable';
import { Node, NodeDimensionUpdate, NodeType, RevueFlowStore } from '../../types';
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
import { computed, defineComponent, h, inject, onMounted, PropType, provide } from 'vue'
import { templateRef, useResizeObserver } from '@vueuse/core'
import { DraggableCore, DraggableEventListener } from '@braks/revue-draggable'
import { Node, NodeDimensionUpdate, NodeType, RevueFlowStore } from '../../types'
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
interface NodeProps {
nodeTypes: Record<string, NodeType>;
snapToGrid: boolean;
snapGrid: [number, number];
selectNodesOnDrag: boolean;
nodeTypes: Record<string, NodeType>
snapToGrid: boolean
snapGrid: [number, number]
selectNodesOnDrag: boolean
}
export default defineComponent({
@@ -39,22 +39,22 @@ export default defineComponent({
}
},
setup(props) {
const store = inject<RevueFlowStore>('store')!;
const hooks = inject<RevueFlowHooks>('hooks')!;
provide('NodeIdContext', props.node.id);
const store = inject<RevueFlowStore>('store')!
const hooks = inject<RevueFlowHooks>('hooks')!
provide('NodeIdContext', props.node.id)
const nodeElement = templateRef<HTMLDivElement>('nodeElement', null);
const nodeElement = templateRef<HTMLDivElement>('nodeElement', null)
const selected = computed(() => store.selectedElements?.some(({ id }) => id === props.node.id) || false);
const selected = computed(() => store.selectedElements?.some(({ id }) => id === props.node.id) || false)
const isDraggable = computed(
() => props.node.draggable || (store.nodesDraggable && typeof props.node.draggable === 'undefined')
);
)
const isSelectable = computed(
() => props.node.selectable || (store.elementsSelectable && typeof props.node.selectable === 'undefined')
);
)
const isConnectable = computed(
() => props.node.connectable || (store.nodesConnectable && typeof props.node.connectable === 'undefined')
);
)
const node = () =>
({
@@ -62,72 +62,72 @@ export default defineComponent({
type: props.node.type,
position: { x: props.node.__rf.position.x, y: props.node.__rf.position.y },
data: props.node.data
} as Node);
} as Node)
const onMouseEnterHandler = () => {
if (props.node.__rf.isDragging) {
return;
return
}
return (event: MouseEvent) => hooks.nodeMouseEnter.trigger({ event, node: node() });
};
return (event: MouseEvent) => hooks.nodeMouseEnter.trigger({ event, node: node() })
}
const onMouseMoveHandler = () => {
if (props.node.__rf.isDragging) {
return;
return
}
return (event: MouseEvent) => hooks.nodeMouseMove.trigger({ event, node: node() });
};
return (event: MouseEvent) => hooks.nodeMouseMove.trigger({ event, node: node() })
}
const onMouseLeaveHandler = () => {
if (props.node.__rf.isDragging) {
return;
return
}
return (event: MouseEvent) => hooks.nodeMouseLeave.trigger({ event, node: node() });
};
return (event: MouseEvent) => hooks.nodeMouseLeave.trigger({ event, node: node() })
}
const onContextMenuHandler = () => {
return (event: MouseEvent) => hooks.nodeContextMenu.trigger({ event, node: node() });
};
return (event: MouseEvent) => hooks.nodeContextMenu.trigger({ event, node: node() })
}
const onSelectNodeHandler = (event: MouseEvent) => {
if (!isDraggable.value) {
const n = node();
const n = node()
if (isSelectable.value) {
store.unsetNodesSelection();
store.unsetNodesSelection()
if (!selected.value) {
store.addSelectedElements([n]);
store.addSelectedElements([n])
}
}
hooks.nodeClick.trigger({ event, node: n });
hooks.nodeClick.trigger({ event, node: n })
}
};
}
const onDragStart: DraggableEventListener = ({ event }) => {
const n = node();
hooks.nodeDragStart.trigger({ event, node: n });
const n = node()
hooks.nodeDragStart.trigger({ event, node: n })
if (props.selectNodesOnDrag && isSelectable.value) {
store.unsetNodesSelection();
store.unsetNodesSelection()
if (!selected.value) {
store.addSelectedElements([n]);
store.addSelectedElements([n])
}
} else if (!props.selectNodesOnDrag && !selected.value && isSelectable.value) {
store.unsetNodesSelection();
store.addSelectedElements([]);
store.unsetNodesSelection()
store.addSelectedElements([])
}
};
}
const onDrag: DraggableEventListener = ({ event, data }) => {
const n = node();
n.position.x += data.deltaX;
n.position.y += data.deltaY;
hooks.nodeDrag.trigger({ event, node: n });
const n = node()
n.position.x += data.deltaX
n.position.y += data.deltaY
hooks.nodeDrag.trigger({ event, node: n })
store?.updateNodePosDiff({
id: props.node.id as string,
@@ -136,39 +136,39 @@ export default defineComponent({
y: data.deltaY
},
isDragging: true
});
};
})
}
const onDragStop: DraggableEventListener = ({ event }) => {
const n = node();
const n = node()
// onDragStop also gets called when user just clicks on a node.
// Because of that we set dragging to true inside the onDrag handler and handle the click here
if (!props.node.__rf.isDragging) {
if (isSelectable.value && !props.selectNodesOnDrag && !selected.value) {
store.addSelectedElements([n]);
store.addSelectedElements([n])
}
hooks.nodeClick.trigger({ event, node: n });
hooks.nodeClick.trigger({ event, node: n })
return;
return
}
store.updateNodePosDiff({
id: n.id || '',
isDragging: false
});
})
hooks.nodeDragStop.trigger({ event, node: n });
};
hooks.nodeDragStop.trigger({ event, node: n })
}
useResizeObserver(nodeElement, (entries) => {
const updates: NodeDimensionUpdate[] = entries.map((entry) => ({
id: entry.target.getAttribute('data-id') || '',
nodeElement: entry.target as HTMLDivElement
}));
}))
store.updateNodeDimensions(updates);
});
store.updateNodeDimensions(updates)
})
onMounted(() => {
store.updateNodeDimensions([
@@ -177,8 +177,8 @@ export default defineComponent({
nodeElement: nodeElement.value,
forceUpdate: true
}
]);
});
])
})
return () =>
props.node.isHidden ? (
@@ -231,6 +231,6 @@ export default defineComponent({
})}
</div>
</DraggableCore>
);
)
}
});
})
+5 -5
View File
@@ -1,6 +1,6 @@
import Handle from '../../components/Handle';
import { NodeProps, NodeType, Position } from '../../types';
import { defineComponent, PropType } from 'vue';
import Handle from '../../components/Handle'
import { NodeProps, NodeType, Position } from '../../types'
import { defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'OutputNode',
@@ -29,6 +29,6 @@ export default defineComponent({
{props.data?.label}
<Handle type="source" position={props.targetPosition} isConnectable={props.isConnectable} />
</>
);
)
}
}) as NodeType;
}) as NodeType
+15 -15
View File
@@ -1,14 +1,14 @@
import { HandleElement, Position } from '../../types';
import { getDimensions } from '../../utils';
import { HandleElement, Position } from '../../types'
import { getDimensions } from '../../utils'
export const getHandleBounds = (nodeElement: HTMLDivElement, scale: number) => {
const bounds = nodeElement.getBoundingClientRect();
const bounds = nodeElement.getBoundingClientRect()
return {
source: getHandleBoundsByHandleType('.source', nodeElement, bounds, scale),
target: getHandleBoundsByHandleType('.target', nodeElement, bounds, scale)
};
};
}
}
export const getHandleBoundsByHandleType = (
selector: string,
@@ -16,19 +16,19 @@ export const getHandleBoundsByHandleType = (
parentBounds: ClientRect | DOMRect,
k: number
): HandleElement[] | null => {
const handles = nodeElement.querySelectorAll(selector);
const handles = nodeElement.querySelectorAll(selector)
if (!handles || !handles.length) {
return null;
return null
}
const handlesArray = Array.from(handles) as HTMLDivElement[];
const handlesArray = Array.from(handles) as HTMLDivElement[]
return handlesArray.map((handle): HandleElement => {
const bounds = handle.getBoundingClientRect();
const dimensions = getDimensions(handle);
const handleId = handle.getAttribute('data-handleid');
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position;
const bounds = handle.getBoundingClientRect()
const dimensions = getDimensions(handle)
const handleId = handle.getAttribute('data-handleid')
const handlePosition = handle.getAttribute('data-handlepos') as unknown as Position
return {
id: handleId,
@@ -36,6 +36,6 @@ export const getHandleBoundsByHandleType = (
x: (bounds.left - parentBounds.left) / k,
y: (bounds.top - parentBounds.top) / k,
...dimensions
};
});
};
}
})
}
+33 -33
View File
@@ -3,56 +3,56 @@
* The nodes selection rectangle gets displayed when a user
* made a selectio with on or several nodes
*/
import { computed, defineComponent, inject } from 'vue';
import { Draggable, DraggableEventListener } from '@braks/revue-draggable';
import { isNode } from '../../utils/graph';
import { Node, RevueFlowStore } from '../../types';
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks';
import { computed, defineComponent, inject } from 'vue'
import { Draggable, DraggableEventListener } from '@braks/revue-draggable'
import { isNode } from '../../utils/graph'
import { Node, RevueFlowStore } from '../../types'
import { RevueFlowHooks } from '../../hooks/RevueFlowHooks'
export interface NodesSelectionProps {
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void;
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void;
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void;
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void;
onSelectionDragStart?: (event: MouseEvent, nodes: Node[]) => void
onSelectionDrag?: (event: MouseEvent, nodes: Node[]) => void
onSelectionDragStop?: (event: MouseEvent, nodes: Node[]) => void
onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void
}
const NodesSelection = defineComponent({
setup() {
const store = inject<RevueFlowStore>('store')!;
const hooks = inject<RevueFlowHooks>('hooks')!;
const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number]);
const transform = computed(() => store.transform);
const store = inject<RevueFlowStore>('store')!
const hooks = inject<RevueFlowHooks>('hooks')!
const grid = computed(() => (store.snapToGrid ? store.snapGrid : [1, 1])! as [number, number])
const transform = computed(() => store.transform)
const selectedNodes = computed(() =>
store.selectedElements
? store.selectedElements.filter(isNode).map((selectedNode) => {
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id);
const matchingNode = store.nodes.find((node) => node.id === selectedNode.id)
return {
...matchingNode,
position: matchingNode?.__rf.position
} as Node;
} as Node
})
: []
);
)
const style = computed(() => ({
transform: `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`
}));
}))
const innerStyle = computed(() => ({
width: `${store.selectedNodesBbox.width}px`,
height: `${store.selectedNodesBbox.height}px`,
top: `${store.selectedNodesBbox.y}px`,
left: `${store.selectedNodesBbox.x}px`
}));
}))
const onStart: DraggableEventListener = ({ event }) => {
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value });
};
hooks.selectionDragStart.trigger({ event, nodes: selectedNodes.value })
}
const onDrag: DraggableEventListener = ({ event, data }) => {
hooks.selectionDrag.trigger({ event, nodes: selectedNodes.value });
hooks.selectionDrag.trigger({ event, nodes: selectedNodes.value })
store.updateNodePosDiff({
diff: {
@@ -60,24 +60,24 @@ const NodesSelection = defineComponent({
y: data.deltaY
},
isDragging: true
});
};
})
}
const onStop: DraggableEventListener = ({ event }) => {
store.updateNodePosDiff({
isDragging: false
});
})
hooks.selectionDragStop.trigger({ event, nodes: selectedNodes.value });
};
hooks.selectionDragStop.trigger({ event, nodes: selectedNodes.value })
}
const onContextMenu = (event: MouseEvent) => {
const selectedNodes: Node[] = store.selectedElements
? store.selectedElements.filter(isNode).map((selectedNode) => store.nodes.find((node) => node.id === selectedNode.id))
: [];
: []
hooks.selectionContextMenu.trigger({ event, nodes: selectedNodes });
};
hooks.selectionContextMenu.trigger({ event, nodes: selectedNodes })
}
return () => {
return !store.selectedElements || store.selectionActive ? (
@@ -95,9 +95,9 @@ const NodesSelection = defineComponent({
<div class="revue-flow__nodesselection-rect" onContextmenu={onContextMenu} style={innerStyle.value} />
</Draggable>
</div>
);
};
)
}
}
});
})
export default NodesSelection;
export default NodesSelection
+33 -33
View File
@@ -1,22 +1,22 @@
/**
* The user selection rectangle gets displayed when a user drags the mouse while pressing shift
*/
import { RevueFlowStore, XYPosition } from '../../types';
import { computed, defineComponent, inject } from 'vue';
import { templateRef, useEventListener } from '@vueuse/core';
import { RevueFlowStore, XYPosition } from '../../types'
import { computed, defineComponent, inject } from 'vue'
import { templateRef, useEventListener } from '@vueuse/core'
function getMousePosition(event: MouseEvent): XYPosition | void {
const revueFlowNode = (event.target as Element).closest('.revue-flow');
const revueFlowNode = (event.target as Element).closest('.revue-flow')
if (!revueFlowNode) {
return;
return
}
const containerBounds = revueFlowNode.getBoundingClientRect();
const containerBounds = revueFlowNode.getBoundingClientRect()
return {
x: event.clientX - containerBounds.left,
y: event.clientY - containerBounds.top
};
}
}
const SelectionRect = (props: { width: number; height: number; x: number; y: number }) => {
@@ -29,51 +29,51 @@ const SelectionRect = (props: { width: number; height: number; x: number; y: num
transform: `translate(${props.x}px, ${props.y}px)`
}}
/>
);
};
)
}
export default defineComponent({
components: { SelectionRect },
setup() {
const store = inject<RevueFlowStore>('store')!;
const el = templateRef('user-selection', null);
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable);
const store = inject<RevueFlowStore>('store')!
const el = templateRef('user-selection', null)
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable)
const onMouseDown = (event: MouseEvent) => {
const mousePos = getMousePosition(event);
const mousePos = getMousePosition(event)
if (!mousePos) {
return;
return
}
store.setUserSelection(mousePos);
};
store.setUserSelection(mousePos)
}
const onMouseMove = (event: MouseEvent) => {
if (!store.selectionActive) {
return;
return
}
const mousePos = getMousePosition(event);
const mousePos = getMousePosition(event)
if (!mousePos) {
return;
return
}
store.updateUserSelection(mousePos);
};
store.updateUserSelection(mousePos)
}
const onMouseUp = () => {
store.unsetUserSelection();
};
store.unsetUserSelection()
}
const onMouseLeave = () => {
store.unsetUserSelection();
store.unsetNodesSelection();
};
store.unsetUserSelection()
store.unsetNodesSelection()
}
useEventListener(el, 'mousedown', onMouseDown);
useEventListener(el, 'mousemove', onMouseMove);
useEventListener(el, 'click', onMouseUp);
useEventListener(el, 'mouseup', onMouseUp);
useEventListener(el, 'mouseleave', onMouseLeave);
useEventListener(el, 'mousedown', onMouseDown)
useEventListener(el, 'mousemove', onMouseMove)
useEventListener(el, 'click', onMouseUp)
useEventListener(el, 'mouseup', onMouseUp)
useEventListener(el, 'mouseleave', onMouseLeave)
return () =>
shouldRender.value ? (
@@ -91,6 +91,6 @@ export default defineComponent({
</div>
) : (
''
);
)
}
});
})