Files
vue-flow/src/components/Nodes/wrapNode.tsx
T
Braks f5580b6d96 feat: Add revue-draggable
refactor: remove vue-draggable
* couple of prop default changes
2021-07-14 15:41:59 +02:00

206 lines
6.3 KiB
TypeScript

import { Node, RevueFlowStore, WrapNodeProps } from '../../types';
import { computed, CSSProperties, defineComponent, inject, onMounted, provide, ref } from 'vue';
import { DraggableCore, DraggableEventHandler } from '@braks/revue-draggable';
export default (NodeComponent: any) => {
return defineComponent({
props: WrapNodeProps,
setup(props) {
const store = inject<RevueFlowStore>('store');
provide('NodeIdContext', props.id);
const nodeElement = ref<HTMLDivElement | undefined>();
const node = computed(() => ({
id: props.id,
type: props.type,
position: { x: props.xPos, y: props.yPos },
data: props.data
}));
const grid = computed(() => (props.snapToGrid ? props.snapGrid : [1, 1])! as [number, number]);
const nodeStyle = computed<CSSProperties>(() => ({
zIndex: props.selected ? 10 : 3,
transform: `translate(${props.xPos}px,${props.yPos}px)`,
pointerEvents:
props.isSelectable ||
props.isDraggable ||
props.onClick ||
props.onMouseEnter ||
props.onMouseMove ||
props.onMouseLeave
? 'all'
: 'none',
// prevents jumping of nodes on start
opacity: props.isInitialized ? 1 : 0,
...props.style
}));
const onMouseEnterHandler = () => {
if (!props.onMouseEnter || props.isDragging) {
return;
}
return (event: MouseEvent) => props.onMouseEnter && props.onMouseEnter(event, node.value as Node);
};
const onMouseMoveHandler = () => {
if (!props.onMouseMove || props.isDragging) {
return;
}
return (event: MouseEvent) => props.onMouseMove && props.onMouseMove(event, node.value as Node);
};
const onMouseLeaveHandler = () => {
if (!props.onMouseLeave || props.isDragging) {
return;
}
return (event: MouseEvent) => props.onMouseLeave && props.onMouseLeave(event, node.value as Node);
};
const onContextMenuHandler = () => {
if (!props.onContextMenu) {
return;
}
return (event: MouseEvent) => props.onContextMenu && props.onContextMenu(event, node.value as Node);
};
const onSelectNodeHandler = (event: MouseEvent) => {
if (!props.isDraggable) {
if (props.isSelectable) {
store?.unsetNodesSelection();
if (!props.selected) {
store?.addSelectedElements([node.value as Node]);
}
}
props.onClick?.(event, node.value as Node);
}
};
const onDragStart: DraggableEventHandler = (event) => {
props.onNodeDragStart?.(event as MouseEvent, node.value as Node);
if (props.selectNodesOnDrag && props.isSelectable) {
store?.unsetNodesSelection();
if (!props.selected) {
store?.addSelectedElements([node.value as Node]);
}
} else if (!props.selectNodesOnDrag && !props.selected && props.isSelectable) {
store?.unsetNodesSelection();
store?.addSelectedElements([]);
}
};
const onDrag: DraggableEventHandler = (event, draggableData) => {
if (props.onNodeDrag) {
node.value.position.x += draggableData.deltaX;
node.value.position.y += draggableData.deltaY;
props.onNodeDrag(event as MouseEvent, node.value as Node);
}
store?.updateNodePosDiff({
id: props.id as string,
diff: {
x: draggableData.deltaX,
y: draggableData.deltaY
},
isDragging: true
});
};
const onDragStop: DraggableEventHandler = (event) => {
// 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.isDragging) {
if (props.isSelectable && !props.selectNodesOnDrag && !props.selected) {
store?.addSelectedElements([node.value as Node]);
}
props.onClick?.(event, node.value as Node);
return;
}
store?.updateNodePosDiff({
id: node.value.id as string,
isDragging: false
});
props.onNodeDragStop?.(event as MouseEvent, node.value as Node);
};
onMounted(() => {
if (nodeElement.value && !props.isHidden) {
store?.updateNodeDimensions([{ id: props.id || '', nodeElement: nodeElement.value, forceUpdate: true }]);
}
});
onMounted(() => {
if (nodeElement.value && typeof props.resizeObserver?.observe === 'function') {
const currNode = nodeElement.value;
props.resizeObserver?.observe(currNode);
return () => props.resizeObserver?.unobserve(currNode);
}
});
if (props.isHidden) {
return null;
}
const nodeClasses = computed(() => [
'revue-flow__node',
`revue-flow__node-${props.type}`,
{
selected: props.selected,
selectable: props.isSelectable
}
]);
return () => (
<DraggableCore
onStart={onDragStart}
onDrag={onDrag}
onStop={onDragStop}
scale={props.scale}
disabled={!props.isDraggable}
cancel=".nodrag"
grid={grid.value}
nodeRef={nodeElement.value}
enableUserSelectHack={false}
>
<div
class={nodeClasses.value}
ref={nodeElement}
style={nodeStyle.value}
onMouseenter={onMouseEnterHandler}
onMousemove={onMouseMoveHandler}
onMouseleave={onMouseLeaveHandler}
onContextmenu={onContextMenuHandler}
onClick={onSelectNodeHandler}
data-id={props.id}
>
<NodeComponent
id={props.id}
data={props.data}
type={props.type}
xPos={props.xPos}
yPos={props.yPos}
selected={props.selected}
isConnectable={props.isConnectable}
sourcePosition={props.sourcePosition}
targetPosition={props.targetPosition}
isDragging={props.isDragging}
/>
</div>
</DraggableCore>
);
}
});
};