/** * The nodes selection rectangle gets displayed when a user * made a selection with on or several nodes */ import { useRef, useEffect, type MouseEvent, type KeyboardEvent } from 'react'; import cc from 'classcat'; import { shallow } from 'zustand/shallow'; import { getNodesBounds } from '@xyflow/system'; import { useStore, useStoreApi } from '../../hooks/useStore'; import { useDrag } from '../../hooks/useDrag'; import { useMoveSelectedNodes } from '../../hooks/useMoveSelectedNodes'; import { arrowKeyDiffs } from '../NodeWrapper/utils'; import type { Node, ReactFlowState } from '../../types'; export type NodesSelectionProps = { onSelectionContextMenu?: (event: MouseEvent, nodes: NodeType[]) => void; noPanClassName?: string; disableKeyboardA11y: boolean; }; const selector = (s: ReactFlowState) => { const selectedNodes = s.nodes.filter((n) => n.selected); const { width, height, x, y } = getNodesBounds(selectedNodes, { nodeOrigin: s.nodeOrigin }); return { width, height, userSelectionActive: s.userSelectionActive, transformString: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]}) translate(${x}px,${y}px)`, }; }; export function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y, }: NodesSelectionProps) { const store = useStoreApi(); const { width, height, transformString, userSelectionActive } = useStore(selector, shallow); const moveSelectedNodes = useMoveSelectedNodes(); const nodeRef = useRef(null); useEffect(() => { if (!disableKeyboardA11y) { nodeRef.current?.focus({ preventScroll: true, }); } }, [disableKeyboardA11y]); useDrag({ nodeRef, }); if (userSelectionActive || !width || !height) { return null; } const onContextMenu = onSelectionContextMenu ? (event: MouseEvent) => { const selectedNodes = store.getState().nodes.filter((n) => n.selected); onSelectionContextMenu(event, selectedNodes); } : undefined; const onKeyDown = (event: KeyboardEvent) => { if (Object.prototype.hasOwnProperty.call(arrowKeyDiffs, event.key)) { moveSelectedNodes({ direction: arrowKeyDiffs[event.key], factor: event.shiftKey ? 4 : 1, }); } }; return (
); }