diff --git a/src/components/Handle/handler.ts b/src/components/Handle/handler.ts index 96196f02..b900369f 100644 --- a/src/components/Handle/handler.ts +++ b/src/components/Handle/handler.ts @@ -11,6 +11,7 @@ import { SetConnectionId, Connection, } from '../../types'; +import { getInitialDocument } from '../../utils/document'; type ValidConnectionFunc = (connection: Connection) => boolean; export type SetSourceIdFunc = (params: SetConnectionId) => void; @@ -31,7 +32,8 @@ function checkElementBelowIsValid( isTarget: boolean, nodeId: ElementId, handleId: ElementId | null, - isValidConnection: ValidConnectionFunc + isValidConnection: ValidConnectionFunc, + document: Document | ShadowRoot ) { const elementBelow = document.elementFromPoint(event.clientX, event.clientY); const elementBelowIsTarget = elementBelow?.classList.contains('target') || false; @@ -95,8 +97,13 @@ export function onMouseDown( connectionMode: ConnectionMode, onConnectStart?: OnConnectStartFunc, onConnectStop?: OnConnectStopFunc, - onConnectEnd?: OnConnectEndFunc + onConnectEnd?: OnConnectEndFunc, + document: Document | ShadowRoot | undefined = getInitialDocument() ): void { + if(!document) { + return; + } + const reactFlowNode = (event.target as Element).closest('.react-flow'); const elementBelow = document.elementFromPoint(event.clientX, event.clientY); const elementBelowIsTarget = elementBelow?.classList.contains('target'); @@ -119,7 +126,7 @@ export function onMouseDown( setConnectionNodeId({ connectionNodeId: nodeId, connectionHandleId: handleId, connectionHandleType: handleType }); onConnectStart?.(event, { nodeId, handleId, handleType }); - function onMouseMove(event: MouseEvent) { + const onMouseMove = (event: MouseEvent) => { setPosition({ x: event.clientX - containerBounds.left, y: event.clientY - containerBounds.top, @@ -131,7 +138,8 @@ export function onMouseDown( isTarget, nodeId, handleId, - isValidConnection + isValidConnection, + document ); if (!isHoveringHandle) { @@ -145,16 +153,17 @@ export function onMouseDown( elementBelow.classList.add('react-flow__handle-connecting'); elementBelow.classList.toggle('react-flow__handle-valid', isValid); } - } + }; - function onMouseUp(event: MouseEvent) { + const onMouseUp = (event: MouseEvent) => { const { connection, isValid } = checkElementBelowIsValid( event, connectionMode, isTarget, nodeId, handleId, - isValidConnection + isValidConnection, + document ); onConnectStop?.(event); @@ -168,10 +177,10 @@ export function onMouseDown( resetRecentHandle(recentHoveredHandle); setConnectionNodeId({ connectionNodeId: null, connectionHandleId: null, connectionHandleType: null }); - document.removeEventListener('mousemove', onMouseMove); - document.removeEventListener('mouseup', onMouseUp); - } + document.removeEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject); + document.removeEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject); + }; - document.addEventListener('mousemove', onMouseMove); - document.addEventListener('mouseup', onMouseUp); + document.addEventListener('mousemove', onMouseMove as EventListenerOrEventListenerObject); + document.addEventListener('mouseup', onMouseUp as EventListenerOrEventListenerObject); } diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx index 0b6da001..c0302bab 100644 --- a/src/components/Handle/index.tsx +++ b/src/components/Handle/index.tsx @@ -28,6 +28,7 @@ const Handle: FC, 'id'>> = ({ const onConnectStop = useStoreState((state) => state.onConnectStop); const onConnectEnd = useStoreState((state) => state.onConnectEnd); const connectionMode = useStoreState((state) => state.connectionMode); + const document = useStoreState(state => state.document); const handleId = id || null; const isTarget = type === 'target'; @@ -53,7 +54,8 @@ const Handle: FC, 'id'>> = ({ connectionMode, onConnectStart, onConnectStop, - onConnectEnd + onConnectEnd, + document ); }, [ @@ -68,6 +70,7 @@ const Handle: FC, 'id'>> = ({ onConnectStart, onConnectStop, onConnectEnd, + document ] ); diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx index 7408d54d..d378a885 100644 --- a/src/container/GraphView/index.tsx +++ b/src/container/GraphView/index.tsx @@ -91,6 +91,7 @@ const GraphView = ({ onEdgeMouseMove, onEdgeMouseLeave, edgeUpdaterRadius, + document, }: GraphViewProps) => { const isInitialized = useRef(false); const setOnConnect = useStoreActions((actions) => actions.setOnConnect); @@ -107,6 +108,7 @@ const GraphView = ({ const setTranslateExtent = useStoreActions((actions) => actions.setTranslateExtent); const setNodeExtent = useStoreActions((actions) => actions.setNodeExtent); const setConnectionMode = useStoreActions((actions) => actions.setConnectionMode); + const setDocument = useStoreActions(actions => actions.setDocument); const currentStore = useStore(); const { zoomIn, zoomOut, zoomTo, transform, fitView, initialized } = useZoomPanHelper(); @@ -129,6 +131,10 @@ const GraphView = ({ } }, [onLoad, zoomIn, zoomOut, zoomTo, transform, fitView, initialized]); + useEffect(() => { + setDocument(document); + }, [document]) + useEffect(() => { if (onConnect) { setOnConnect(onConnect); diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 809fef98..92aca0fa 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -35,6 +35,7 @@ import { import '../../style.css'; import '../../theme-default.css'; +import { getInitialDocument } from '../../utils/document'; const defaultNodeTypes = { input: InputNode, @@ -115,6 +116,7 @@ export interface ReactFlowProps extends Omit, 'on onEdgeMouseMove?: (event: MouseEvent, edge: Edge) => void; onEdgeMouseLeave?: (event: MouseEvent, edge: Edge) => void; edgeUpdaterRadius?: number; + document?: Document | ShadowRoot; nodeTypesId?: string; edgeTypesId?: string; } @@ -189,6 +191,7 @@ const ReactFlow = ({ edgeUpdaterRadius = 10, nodeTypesId = '1', edgeTypesId = '1', + document = getInitialDocument(), ...rest }: ReactFlowProps) => { const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), [nodeTypesId]); @@ -262,6 +265,7 @@ const ReactFlow = ({ onEdgeMouseMove={onEdgeMouseMove} onEdgeMouseLeave={onEdgeMouseLeave} edgeUpdaterRadius={edgeUpdaterRadius} + document={document} /> {onSelectionChange && } diff --git a/src/store/actions.ts b/src/store/actions.ts index 0f6bbc47..d68f9a74 100644 --- a/src/store/actions.ts +++ b/src/store/actions.ts @@ -42,6 +42,11 @@ export const setOnConnectEnd = (onConnectEnd: OnConnectEndFunc) => onConnectEnd, }); +export const setDocument = (document: Document | ShadowRoot) => + createAction(constants.SET_DOCUMENT, { + document + }) + export const setElements = (elements: Elements) => createAction(constants.SET_ELEMENTS, elements); export const updateNodeDimensions = (updates: NodeDimensionUpdate[]) => @@ -160,4 +165,5 @@ export type ReactFlowAction = ReturnType< | typeof setMultiSelectionActive | typeof setConnectionMode | typeof setNodeExtent + | typeof setDocument >; diff --git a/src/store/contants.ts b/src/store/contants.ts index 389432df..168139bb 100644 --- a/src/store/contants.ts +++ b/src/store/contants.ts @@ -31,3 +31,4 @@ export const SET_ELEMENTS_SELECTABLE = 'SET_ELEMENTS_SELECTABLE'; export const SET_MULTI_SELECTION_ACTIVE = 'SET_MULTI_SELECTION_ACTIVE'; export const SET_CONNECTION_MODE = 'SET_CONNECTION_MODE'; export const SET_NODE_EXTENT = 'SET_NODE_EXTENT'; +export const SET_DOCUMENT = 'SET_DOCUMENT'; diff --git a/src/store/index.ts b/src/store/index.ts index 6640d9e0..4f317ce1 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,8 +1,10 @@ import configureStore from './configure-store'; import { ReactFlowState, ConnectionMode } from '../types'; +import { getInitialDocument } from '../utils/document'; export const initialState: ReactFlowState = { + document: getInitialDocument(), width: 0, height: 0, transform: [0, 0, 1], diff --git a/src/store/reducer.ts b/src/store/reducer.ts index 57d4ea97..245a64d6 100644 --- a/src/store/reducer.ts +++ b/src/store/reducer.ts @@ -334,6 +334,7 @@ export default function reactFlowReducer(state = initialState, action: ReactFlow case constants.SET_ELEMENTS_SELECTABLE: case constants.SET_MULTI_SELECTION_ACTIVE: case constants.SET_CONNECTION_MODE: + case constants.SET_DOCUMENT: return { ...state, ...action.payload }; default: return state; diff --git a/src/types/index.ts b/src/types/index.ts index cbf38518..0deb7992 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -430,6 +430,8 @@ export interface ReactFlowState { onConnectStart?: OnConnectStartFunc; onConnectStop?: OnConnectStopFunc; onConnectEnd?: OnConnectEndFunc; + + document?: Document | ShadowRoot; } export type UpdateNodeInternals = (nodeId: ElementId) => void; diff --git a/src/utils/document.ts b/src/utils/document.ts new file mode 100644 index 00000000..a7f4c8b1 --- /dev/null +++ b/src/utils/document.ts @@ -0,0 +1 @@ +export const getInitialDocument = () => typeof window === 'undefined' ? undefined : window.document