implemented keyboard interactions
This commit is contained in:
@@ -12,7 +12,9 @@ import {
|
||||
type CoordinateExtent,
|
||||
type UpdateConnection,
|
||||
type ConnectionState,
|
||||
updateAbsolutePositions
|
||||
updateAbsolutePositions,
|
||||
snapPosition,
|
||||
calculateNodePosition
|
||||
} from '@xyflow/system';
|
||||
|
||||
import type { EdgeTypes, NodeTypes, Node, Edge, FitViewOptions } from '$lib/types';
|
||||
@@ -247,7 +249,7 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
}
|
||||
}
|
||||
|
||||
function handleNodeSelection(id: string) {
|
||||
function handleNodeSelection(id: string, unselect?: boolean, nodeRef?: HTMLDivElement | null) {
|
||||
const node = store.nodeLookup.get(id);
|
||||
|
||||
if (!node) {
|
||||
@@ -260,8 +262,10 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
|
||||
if (!node.selected) {
|
||||
addSelectedNodes([id]);
|
||||
} else if (node.selected && store.multiselectionKeyPressed) {
|
||||
} else if (unselect || (node.selected && store.multiselectionKeyPressed)) {
|
||||
unselectNodesAndEdges({ nodes: [node], edges: [] });
|
||||
|
||||
requestAnimationFrame(() => nodeRef?.blur());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,6 +292,55 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
}
|
||||
}
|
||||
|
||||
function moveSelectedNodes(direction: XYPosition, factor: number) {
|
||||
const { nodeExtent, snapGrid, nodeOrigin, nodeLookup, nodesDraggable, onerror } = store;
|
||||
|
||||
const nodeUpdates = new Map();
|
||||
/*
|
||||
* by default a node moves 5px on each key press
|
||||
* if snap grid is enabled, we use that for the velocity
|
||||
*/
|
||||
const xVelo = snapGrid?.[0] ?? 5;
|
||||
const yVelo = snapGrid?.[1] ?? 5;
|
||||
|
||||
const xDiff = direction.x * xVelo * factor;
|
||||
const yDiff = direction.y * yVelo * factor;
|
||||
|
||||
for (const node of nodeLookup.values()) {
|
||||
const isSelected =
|
||||
node.selected &&
|
||||
(node.draggable || (nodesDraggable && typeof node.draggable === 'undefined'));
|
||||
|
||||
if (!isSelected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let nextPosition = {
|
||||
x: node.internals.positionAbsolute.x + xDiff,
|
||||
y: node.internals.positionAbsolute.y + yDiff
|
||||
};
|
||||
|
||||
if (snapGrid) {
|
||||
nextPosition = snapPosition(nextPosition, snapGrid);
|
||||
}
|
||||
|
||||
const { position, positionAbsolute } = calculateNodePosition({
|
||||
nodeId: node.id,
|
||||
nextPosition,
|
||||
nodeLookup,
|
||||
nodeExtent,
|
||||
nodeOrigin,
|
||||
onError: onerror
|
||||
});
|
||||
|
||||
node.position = position;
|
||||
node.internals.positionAbsolute = positionAbsolute;
|
||||
|
||||
nodeUpdates.set(node.id, node);
|
||||
}
|
||||
updateNodePositions(nodeUpdates);
|
||||
}
|
||||
|
||||
function panBy(delta: XYPosition) {
|
||||
return panBySystem({
|
||||
delta,
|
||||
@@ -335,6 +388,7 @@ export function createStore(signals: StoreSignals): SvelteFlowStore {
|
||||
addSelectedEdges,
|
||||
handleNodeSelection,
|
||||
handleEdgeSelection,
|
||||
moveSelectedNodes,
|
||||
panBy,
|
||||
updateConnection,
|
||||
cancelConnection,
|
||||
|
||||
@@ -196,6 +196,10 @@ export const getInitialStore = (signals: StoreSignals) => {
|
||||
nodesDraggable: boolean = $derived(signals.props.nodesDraggable ?? true);
|
||||
nodesConnectable: boolean = $derived(signals.props.nodesConnectable ?? true);
|
||||
elementsSelectable: boolean = $derived(signals.props.elementsSelectable ?? true);
|
||||
nodesFocusable: boolean = $derived(signals.props.nodesFocusable ?? true);
|
||||
edgesFocusable: boolean = $derived(signals.props.edgesFocusable ?? true);
|
||||
|
||||
disableKeyboardA11y: boolean = $derived(signals.props.disableKeyboardA11y ?? false);
|
||||
|
||||
minZoom: number = $derived(signals.props.minZoom ?? 0.5);
|
||||
maxZoom: number = $derived(signals.props.maxZoom ?? 2);
|
||||
|
||||
@@ -29,8 +29,9 @@ export type SvelteFlowStoreActions = {
|
||||
unselectNodesAndEdges: (params?: { nodes?: Node[]; edges?: Edge[] }) => void;
|
||||
addSelectedNodes: (ids: string[]) => void;
|
||||
addSelectedEdges: (ids: string[]) => void;
|
||||
handleNodeSelection: (id: string) => void;
|
||||
handleNodeSelection: (id: string, unselect?: boolean, nodeRef?: HTMLDivElement | null) => void;
|
||||
handleEdgeSelection: (id: string) => void;
|
||||
moveSelectedNodes: (direction: XYPosition, factor: number) => void;
|
||||
panBy: (delta: XYPosition) => Promise<boolean>;
|
||||
updateConnection: UpdateConnection;
|
||||
cancelConnection: () => void;
|
||||
|
||||
Reference in New Issue
Block a user