fix: node selection rect not properly rendering on key press and mousemove
* issue came from some reactivity problems; a component shouldn't return null, else it'll basically do nothing ever again if it's not completely remounted * some type fixes, removed some any's
This commit is contained in:
@@ -21,6 +21,7 @@ const NodesSelection = ({
|
|||||||
onSelectionContextMenu
|
onSelectionContextMenu
|
||||||
}: NodesSelectionProps) => {
|
}: NodesSelectionProps) => {
|
||||||
const store = inject<RevueFlowStore>('store');
|
const store = inject<RevueFlowStore>('store');
|
||||||
|
console.log('nodesSelection');
|
||||||
|
|
||||||
const nodeRef = ref<HTMLElement | undefined>();
|
const nodeRef = ref<HTMLElement | undefined>();
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,7 @@
|
|||||||
* The user selection rectangle gets displayed when a user drags the mouse while pressing shift
|
* The user selection rectangle gets displayed when a user drags the mouse while pressing shift
|
||||||
*/
|
*/
|
||||||
import { RevueFlowStore, XYPosition } from '../../types';
|
import { RevueFlowStore, XYPosition } from '../../types';
|
||||||
import { computed, defineComponent, inject, PropType } from 'vue';
|
import { computed, defineComponent, inject } from 'vue';
|
||||||
|
|
||||||
type UserSelectionProps = {
|
|
||||||
selectionKeyPressed: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
function getMousePosition(event: MouseEvent): XYPosition | void {
|
function getMousePosition(event: MouseEvent): XYPosition | void {
|
||||||
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
const revueFlowNode = (event.target as Element).closest('.revue-flow');
|
||||||
@@ -26,38 +22,29 @@ const SelectionRect = defineComponent({
|
|||||||
setup() {
|
setup() {
|
||||||
const store = inject<RevueFlowStore>('store');
|
const store = inject<RevueFlowStore>('store');
|
||||||
|
|
||||||
if (!store?.userSelectionRect.draw) {
|
return () => {
|
||||||
return null;
|
return store?.userSelectionRect.draw ? (
|
||||||
}
|
<div
|
||||||
|
class="revue-flow__selection"
|
||||||
return () => (
|
style={{
|
||||||
<div
|
width: `${store?.userSelectionRect.width}px`,
|
||||||
class="revue-flow__selection"
|
height: `${store?.userSelectionRect.height}px`,
|
||||||
style={{
|
transform: `translate(${store?.userSelectionRect.x}px, ${store?.userSelectionRect.y}px)`
|
||||||
width: `${store?.userSelectionRect.width}px`,
|
}}
|
||||||
height: `${store?.userSelectionRect.height}px`,
|
/>
|
||||||
transform: `translate(${store?.userSelectionRect.x}px, ${store?.userSelectionRect.y}px)`
|
) : (
|
||||||
}}
|
''
|
||||||
/>
|
);
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { SelectionRect },
|
components: { SelectionRect },
|
||||||
props: {
|
setup() {
|
||||||
selectionKeyPressed: {
|
|
||||||
type: Boolean as PropType<UserSelectionProps['selectionKeyPressed']>,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const store = inject<RevueFlowStore>('store')!;
|
const store = inject<RevueFlowStore>('store')!;
|
||||||
const renderUserSelectionPane = computed(() => {
|
|
||||||
return props.selectionKeyPressed || store.selectionActive;
|
|
||||||
});
|
|
||||||
|
|
||||||
const shouldRender = computed(() => renderUserSelectionPane.value || store.elementsSelectable);
|
const shouldRender = computed(() => store.selectionActive || store.elementsSelectable);
|
||||||
|
|
||||||
if (!shouldRender.value) {
|
if (!shouldRender.value) {
|
||||||
return null;
|
return null;
|
||||||
@@ -69,11 +56,12 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('mouseDown');
|
||||||
store?.setUserSelection(mousePos);
|
store?.setUserSelection(mousePos);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseMove = (event: MouseEvent): void => {
|
const onMouseMove = (event: MouseEvent): void => {
|
||||||
if (!props.selectionKeyPressed || !store?.selectionActive) {
|
if (!store?.selectionActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const mousePos = getMousePosition(event);
|
const mousePos = getMousePosition(event);
|
||||||
@@ -81,11 +69,15 @@ export default defineComponent({
|
|||||||
if (!mousePos) {
|
if (!mousePos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log('mousemove');
|
||||||
|
|
||||||
store?.updateUserSelection(mousePos);
|
store?.updateUserSelection(mousePos);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseUp = () => store?.unsetUserSelection();
|
const onMouseUp = () => {
|
||||||
|
console.log('mosueUp');
|
||||||
|
store?.unsetUserSelection();
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseLeave = () => {
|
const onMouseLeave = () => {
|
||||||
store?.unsetUserSelection();
|
store?.unsetUserSelection();
|
||||||
@@ -97,6 +89,7 @@ export default defineComponent({
|
|||||||
class="revue-flow__selectionpane"
|
class="revue-flow__selectionpane"
|
||||||
onMousedown={onMouseDown}
|
onMousedown={onMouseDown}
|
||||||
onMousemove={onMouseMove}
|
onMousemove={onMouseMove}
|
||||||
|
onClick={onMouseUp}
|
||||||
onMouseup={onMouseUp}
|
onMouseup={onMouseUp}
|
||||||
onMouseleave={onMouseLeave}
|
onMouseleave={onMouseLeave}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -27,57 +27,57 @@ const FlowRenderer = defineComponent({
|
|||||||
onPaneClick: {
|
onPaneClick: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onPaneClick']>,
|
type: Function as unknown as PropType<FlowRendererProps['onPaneClick']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onPaneContextMenu: {
|
onPaneContextMenu: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onPaneContextMenu']>,
|
type: Function as unknown as PropType<FlowRendererProps['onPaneContextMenu']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onPaneScroll: {
|
onPaneScroll: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onPaneScroll']>,
|
type: Function as unknown as PropType<FlowRendererProps['onPaneScroll']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onElementsRemove: {
|
onElementsRemove: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onElementsRemove']>,
|
type: Function as unknown as PropType<FlowRendererProps['onElementsRemove']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onMove: {
|
onMove: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onMove']>,
|
type: Function as unknown as PropType<FlowRendererProps['onMove']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onMoveStart: {
|
onMoveStart: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onMoveStart']>,
|
type: Function as unknown as PropType<FlowRendererProps['onMoveStart']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onMoveEnd: {
|
onMoveEnd: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onMoveEnd']>,
|
type: Function as unknown as PropType<FlowRendererProps['onMoveEnd']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onSelectionDragStart: {
|
onSelectionDragStart: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onSelectionDragStart']>,
|
type: Function as unknown as PropType<FlowRendererProps['onSelectionDragStart']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onSelectionDrag: {
|
onSelectionDrag: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onSelectionDrag']>,
|
type: Function as unknown as PropType<FlowRendererProps['onSelectionDrag']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onSelectionDragStop: {
|
onSelectionDragStop: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onSelectionDragStop']>,
|
type: Function as unknown as PropType<FlowRendererProps['onSelectionDragStop']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onSelectionContextMenu: {
|
onSelectionContextMenu: {
|
||||||
type: Function as unknown as PropType<FlowRendererProps['onSelectionContextMenu']>,
|
type: Function as unknown as PropType<FlowRendererProps['onSelectionContextMenu']>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
deleteKeyCode: {
|
deleteKeyCode: {
|
||||||
type: [Number, String] as PropType<FlowRendererProps['deleteKeyCode']>,
|
type: [Number, String] as PropType<FlowRendererProps['deleteKeyCode']>,
|
||||||
@@ -184,7 +184,7 @@ const FlowRenderer = defineComponent({
|
|||||||
onMove={props.onMove}
|
onMove={props.onMove}
|
||||||
onMoveStart={props.onMoveStart}
|
onMoveStart={props.onMoveStart}
|
||||||
onMoveEnd={props.onMoveEnd}
|
onMoveEnd={props.onMoveEnd}
|
||||||
selectionKeyPressed={false}
|
selectionKeyPressed={keyPressed.value}
|
||||||
elementsSelectable={props.elementsSelectable}
|
elementsSelectable={props.elementsSelectable}
|
||||||
zoomOnScroll={props.zoomOnScroll}
|
zoomOnScroll={props.zoomOnScroll}
|
||||||
zoomOnPinch={props.zoomOnPinch}
|
zoomOnPinch={props.zoomOnPinch}
|
||||||
@@ -199,7 +199,7 @@ const FlowRenderer = defineComponent({
|
|||||||
zoomActivationKeyCode={props.zoomActivationKeyCode}
|
zoomActivationKeyCode={props.zoomActivationKeyCode}
|
||||||
>
|
>
|
||||||
{slots.default ? slots.default() : ''}
|
{slots.default ? slots.default() : ''}
|
||||||
{keyPressed.value ? <UserSelection selectionKeyPressed={keyPressed.value} /> : ''}
|
{keyPressed.value ? <UserSelection track-by={'selection'} /> : ''}
|
||||||
{store?.nodesSelectionActive && (
|
{store?.nodesSelectionActive && (
|
||||||
<NodesSelection
|
<NodesSelection
|
||||||
onSelectionDragStart={props.onSelectionDragStart}
|
onSelectionDragStart={props.onSelectionDragStart}
|
||||||
|
|||||||
@@ -485,12 +485,12 @@ const RevueFlow = defineComponent({
|
|||||||
onDrop: {
|
onDrop: {
|
||||||
type: Function as unknown as PropType<(e: DragEvent) => any>,
|
type: Function as unknown as PropType<(e: DragEvent) => any>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
},
|
},
|
||||||
onDragover: {
|
onDragover: {
|
||||||
type: Function as unknown as PropType<(e: DragEvent) => any>,
|
type: Function as unknown as PropType<(e: DragEvent) => any>,
|
||||||
required: false,
|
required: false,
|
||||||
default: undefined as any
|
default: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/* // focus events
|
/* // focus events
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { select, pointer } from 'd3-selection';
|
|||||||
|
|
||||||
import { clamp } from '../../utils';
|
import { clamp } from '../../utils';
|
||||||
import { FlowTransform, TranslateExtent, PanOnScrollMode, KeyCode } from '../../types';
|
import { FlowTransform, TranslateExtent, PanOnScrollMode, KeyCode } from '../../types';
|
||||||
import { defineComponent, onMounted, PropType, ref, watch } from 'vue';
|
import { defineComponent, onMounted, PropType, ref, watch, watchEffect } from 'vue';
|
||||||
import store from '../../store';
|
import store from '../../store';
|
||||||
import useKeyPress from '../../hooks/useKeyPress';
|
import useKeyPress from '../../hooks/useKeyPress';
|
||||||
import useResizeHandler from '../../hooks/useResizeHandler';
|
import useResizeHandler from '../../hooks/useResizeHandler';
|
||||||
@@ -193,7 +193,7 @@ const ZoomPane = defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
watchEffect(() => {
|
||||||
if (pinia.d3Zoom) {
|
if (pinia.d3Zoom) {
|
||||||
if (props.selectionKeyPressed) {
|
if (props.selectionKeyPressed) {
|
||||||
pinia.d3Zoom.on('zoom', null);
|
pinia.d3Zoom.on('zoom', null);
|
||||||
@@ -210,7 +210,7 @@ const ZoomPane = defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
watchEffect(() => {
|
||||||
if (pinia.d3Zoom) {
|
if (pinia.d3Zoom) {
|
||||||
if (props.onMoveStart) {
|
if (props.onMoveStart) {
|
||||||
pinia.d3Zoom.on('start', (event: any) => {
|
pinia.d3Zoom.on('start', (event: any) => {
|
||||||
@@ -227,7 +227,7 @@ const ZoomPane = defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
watchEffect(() => {
|
||||||
if (pinia.d3Zoom) {
|
if (pinia.d3Zoom) {
|
||||||
if (props.onMoveEnd) {
|
if (props.onMoveEnd) {
|
||||||
pinia.d3Zoom.on('end', (event: any) => {
|
pinia.d3Zoom.on('end', (event: any) => {
|
||||||
@@ -244,7 +244,7 @@ const ZoomPane = defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
watchEffect(() => {
|
||||||
if (pinia.d3Zoom) {
|
if (pinia.d3Zoom) {
|
||||||
pinia.d3Zoom.filter((event: any) => {
|
pinia.d3Zoom.filter((event: any) => {
|
||||||
const zoomScroll = props.zoomOnScroll;
|
const zoomScroll = props.zoomOnScroll;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import useKeyPress from './useKeyPress';
|
import useKeyPress from './useKeyPress';
|
||||||
import { isNode, getConnectedEdges } from '../utils/graph';
|
import { isNode, getConnectedEdges } from '../utils/graph';
|
||||||
import { Elements, KeyCode, ElementId, FlowElement, RevueFlowStore } from '../types';
|
import { Elements, KeyCode, ElementId, FlowElement, RevueFlowStore, Edge } from '../types';
|
||||||
import { inject, onMounted } from 'vue';
|
import { computed, inject, watch } from 'vue';
|
||||||
|
|
||||||
interface HookParams {
|
interface HookParams {
|
||||||
deleteKeyCode: KeyCode;
|
deleteKeyCode: KeyCode;
|
||||||
@@ -14,12 +14,14 @@ export default ({ deleteKeyCode, multiSelectionKeyCode, onElementsRemove }: Hook
|
|||||||
|
|
||||||
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
const deleteKeyPressed = useKeyPress(deleteKeyCode);
|
||||||
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
|
const multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
|
||||||
|
const selectedElements = computed(() => store?.selectedElements || []);
|
||||||
|
const edges = computed(() => store?.edges);
|
||||||
|
|
||||||
onMounted(() => {
|
watch(selectedElements, () => {
|
||||||
if (onElementsRemove && deleteKeyPressed.value && store?.selectedElements) {
|
if (onElementsRemove && deleteKeyPressed.value && selectedElements.value.length > 0) {
|
||||||
const selectedNodes = store?.selectedElements.filter(isNode);
|
const selectedNodes = selectedElements.value.filter(isNode);
|
||||||
const connectedEdges = getConnectedEdges(selectedNodes, store?.edges);
|
const connectedEdges = getConnectedEdges(selectedNodes, edges.value as Edge[]);
|
||||||
const elementsToRemove = [...store?.selectedElements, ...connectedEdges].reduce(
|
const elementsToRemove = [...selectedElements.value, ...connectedEdges].reduce(
|
||||||
(res, item) => res.set(item.id, item),
|
(res, item) => res.set(item.id, item),
|
||||||
new Map<ElementId, FlowElement>()
|
new Map<ElementId, FlowElement>()
|
||||||
);
|
);
|
||||||
@@ -30,7 +32,7 @@ export default ({ deleteKeyCode, multiSelectionKeyCode, onElementsRemove }: Hook
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
watch(multiSelectionKeyPressed, () => {
|
||||||
store?.setMultiSelectionActive(multiSelectionKeyPressed.value);
|
store?.setMultiSelectionActive(multiSelectionKeyPressed.value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
|
"jsxFactory": "",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user