fix(system): safe check all event target
This commit is contained in:
@@ -47,7 +47,7 @@ const AddNodeOnEdgeDrop = () => {
|
|||||||
(event) => {
|
(event) => {
|
||||||
if (!connectingNodeId.current) return;
|
if (!connectingNodeId.current) return;
|
||||||
|
|
||||||
const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('react-flow__pane');
|
const targetIsPane = (event.target as Partial<Element> | null)?.classList?.contains('react-flow__pane');
|
||||||
|
|
||||||
if (targetIsPane && 'clientX' in event && 'clientY' in event) {
|
if (targetIsPane && 'clientX' in event && 'clientY' in event) {
|
||||||
// we need to remove the wrapper bounds, in order to get the correct position
|
// we need to remove the wrapper bounds, in order to get the correct position
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
if (!connectingNodeId) return;
|
if (!connectingNodeId) return;
|
||||||
|
|
||||||
// See of connection landed inside the flow pane
|
// See of connection landed inside the flow pane
|
||||||
const targetIsPane = (event.target as HTMLDivElement)?.classList.contains('svelte-flow__pane');
|
const targetIsPane = (event.target as Partial<Element> | null)?.classList?.contains('svelte-flow__pane');
|
||||||
if (targetIsPane && 'clientX' in event && 'clientY' in event) {
|
if (targetIsPane && 'clientX' in event && 'clientY' in event) {
|
||||||
const id = getId();
|
const id = getId();
|
||||||
const position = {
|
const position = {
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ function HandleComponent(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc = getHostForElement(event.target as HTMLElement);
|
const doc = getHostForElement(event.target);
|
||||||
const isValidConnectionHandler = isValidConnection || isValidConnectionStore;
|
const isValidConnectionHandler = isValidConnection || isValidConnectionStore;
|
||||||
const { connection, isValid } = XYHandle.isValid(event.nativeEvent, {
|
const { connection, isValid } = XYHandle.isValid(event.nativeEvent, {
|
||||||
handle: {
|
handle: {
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export function Pane({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(event.target as Element)?.setPointerCapture?.(event.pointerId);
|
(event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId);
|
||||||
|
|
||||||
selectionStarted.current = true;
|
selectionStarted.current = true;
|
||||||
selectionInProgress.current = false;
|
selectionInProgress.current = false;
|
||||||
@@ -229,7 +229,7 @@ export function Pane({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(event.target as Element)?.releasePointerCapture?.(event.pointerId);
|
(event.target as Partial<Element>)?.releasePointerCapture?.(event.pointerId);
|
||||||
const { userSelectionRect } = store.getState();
|
const { userSelectionRect } = store.getState();
|
||||||
// We only want to trigger click functions when in selection mode if
|
// We only want to trigger click functions when in selection mode if
|
||||||
// the user did not move the mouse.
|
// the user did not move the mouse.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(event.target as Element)?.setPointerCapture?.(event.pointerId);
|
(event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId);
|
||||||
|
|
||||||
const { x, y } = getEventPosition(event, containerBounds);
|
const { x, y } = getEventPosition(event, containerBounds);
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(event.target as Element)?.releasePointerCapture?.(event.pointerId);
|
(event.target as Partial<Element> | null)?.releasePointerCapture?.(event.pointerId);
|
||||||
|
|
||||||
// We only want to trigger click functions when in selection mode if
|
// We only want to trigger click functions when in selection mode if
|
||||||
// the user did not move the mouse.
|
// the user did not move the mouse.
|
||||||
|
|||||||
@@ -32,18 +32,20 @@ export const getDimensions = (node: HTMLDivElement): Dimensions => ({
|
|||||||
height: node.offsetHeight,
|
height: node.offsetHeight,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getHostForElement = (element: HTMLElement): Document | ShadowRoot =>
|
export const getHostForElement = (element: HTMLElement | EventTarget | null): Document | ShadowRoot =>
|
||||||
(element.getRootNode?.() as Document | ShadowRoot) || window?.document;
|
((element as Partial<HTMLElement> | null)?.getRootNode?.() as Document | ShadowRoot) || window?.document;
|
||||||
|
|
||||||
const inputTags = ['INPUT', 'SELECT', 'TEXTAREA'];
|
const inputTags = ['INPUT', 'SELECT', 'TEXTAREA'];
|
||||||
|
|
||||||
export function isInputDOMNode(event: KeyboardEvent): boolean {
|
export function isInputDOMNode(event: KeyboardEvent): boolean {
|
||||||
// using composed path for handling shadow dom
|
// using composed path for handling shadow dom
|
||||||
const target = (event.composedPath?.()?.[0] || event.target) as HTMLElement;
|
const target = (event.composedPath?.()?.[0] || event.target) as Element | null;
|
||||||
const isInput = inputTags.includes(target?.nodeName) || target?.hasAttribute?.('contenteditable');
|
if (target?.nodeType !== 1 /* Node.ELEMENT_NODE */) return false;
|
||||||
|
|
||||||
|
const isInput = inputTags.includes(target.nodeName) || target.hasAttribute('contenteditable');
|
||||||
|
|
||||||
// when an input field is focused we don't want to trigger deletion or movement of nodes
|
// when an input field is focused we don't want to trigger deletion or movement of nodes
|
||||||
return isInput || !!target?.closest('.nokey');
|
return isInput || !!target.closest('.nokey');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isMouseEvent = (event: MouseEvent | TouchEvent): event is MouseEvent => 'clientX' in event;
|
export const isMouseEvent = (event: MouseEvent | TouchEvent): event is MouseEvent => 'clientX' in event;
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((event: MouseEvent) => {
|
.filter((event: MouseEvent) => {
|
||||||
const target = event.target as HTMLDivElement;
|
const target = event.target;
|
||||||
const isDraggable =
|
const isDraggable =
|
||||||
!event.button &&
|
!event.button &&
|
||||||
(!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) &&
|
(!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) &&
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ export function isParentSelected<NodeType extends NodeBase>(node: NodeType, node
|
|||||||
return isParentSelected(parentNode, nodeLookup);
|
return isParentSelected(parentNode, nodeLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasSelector(target: Element, selector: string, domNode: Element): boolean {
|
export function hasSelector(target: Element | EventTarget | null, selector: string, domNode: Element): boolean {
|
||||||
let current = target;
|
let current = target as Partial<Element> | null | undefined;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (current?.matches(selector)) return true;
|
if (current?.matches?.(selector)) return true;
|
||||||
if (current === domNode) return false;
|
if (current === domNode) return false;
|
||||||
current = current.parentElement as Element;
|
current = current?.parentElement;
|
||||||
} while (current);
|
} while (current);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function onPointerDown(
|
|||||||
}: OnPointerDownParams
|
}: OnPointerDownParams
|
||||||
) {
|
) {
|
||||||
// when xyflow is used inside a shadow root we can't use document
|
// when xyflow is used inside a shadow root we can't use document
|
||||||
const doc = getHostForElement(event.target as HTMLElement);
|
const doc = getHostForElement(event.target);
|
||||||
let autoPanId = 0;
|
let autoPanId = 0;
|
||||||
let closestHandle: Handle | null;
|
let closestHandle: Handle | null;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user