refactor(selection): make it possible to start a selection above a node #5342

This commit is contained in:
moklick
2025-10-15 15:15:07 +02:00
parent d9de28214a
commit 75aff8ef26
3 changed files with 35 additions and 11 deletions
@@ -30,7 +30,7 @@ function ColorSelectorNode({ data, isConnectable }: NodeProps<ColorSelectorNode>
<div> <div>
Custom Color Picker Node: <strong>{data.color}</strong> Custom Color Picker Node: <strong>{data.color}</strong>
</div> </div>
<input className="nodrag" type="color" onChange={data.onChange} defaultValue={data.color} /> <input className="nodrag nokey" type="color" onChange={data.onChange} defaultValue={data.color} />
<Handle <Handle
type="source" type="source"
position={Position.Right} position={Position.Right}
+34 -9
View File
@@ -95,6 +95,8 @@ export function Pane({
const selectionInProgress = useRef<boolean>(false); const selectionInProgress = useRef<boolean>(false);
const selectionStarted = useRef<boolean>(false); const selectionStarted = useRef<boolean>(false);
const isNoKeyEvent = useRef<boolean | null>(null);
const onClick = (event: ReactMouseEvent) => { const onClick = (event: ReactMouseEvent) => {
// We prevent click events when the user let go of the selectionKey during a selection // We prevent click events when the user let go of the selectionKey during a selection
// We also prevent click events when a connection is in progress // We also prevent click events when a connection is in progress
@@ -119,20 +121,40 @@ export function Pane({
const onWheel = onPaneScroll ? (event: React.WheelEvent) => onPaneScroll(event) : undefined; const onWheel = onPaneScroll ? (event: React.WheelEvent) => onPaneScroll(event) : undefined;
const onMouseDownCapture = (event: ReactMouseEvent) => {
isNoKeyEvent.current =
isNoKeyEvent.current === null ? !!(event.target as HTMLElement).closest('.nokey') : isNoKeyEvent.current;
if (isNoKeyEvent.current) {
return;
}
event.stopPropagation();
};
const onClickCapture = (event: ReactMouseEvent) => {
if (isNoKeyEvent.current) {
isNoKeyEvent.current = null;
return;
}
isNoKeyEvent.current = null;
event.stopPropagation();
};
const onPointerDown = (event: ReactPointerEvent): void => { const onPointerDown = (event: ReactPointerEvent): void => {
const { resetSelectedElements, domNode } = store.getState(); const { resetSelectedElements, domNode } = store.getState();
containerBounds.current = domNode?.getBoundingClientRect(); containerBounds.current = domNode?.getBoundingClientRect();
isNoKeyEvent.current =
isNoKeyEvent.current === null ? !!(event.target as HTMLElement).closest('.nokey') : isNoKeyEvent.current;
if ( if (!elementsSelectable || !isSelecting || event.button !== 0 || !containerBounds.current || isNoKeyEvent.current) {
!elementsSelectable ||
!isSelecting ||
event.button !== 0 ||
event.target !== container.current ||
!containerBounds.current
) {
return; return;
} }
event.stopPropagation();
(event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId); (event.target as Partial<Element> | null)?.setPointerCapture?.(event.pointerId);
selectionStarted.current = true; selectionStarted.current = true;
@@ -234,7 +256,7 @@ export function Pane({
(event.target as Partial<Element>)?.releasePointerCapture?.(event.pointerId); (event.target as Partial<Element>)?.releasePointerCapture?.(event.pointerId);
const { userSelectionRect } = store.getState(); const { userSelectionRect } = store.getState();
isNoKeyEvent.current = null;
/* /*
* 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.
@@ -270,9 +292,12 @@ export function Pane({
onContextMenu={wrapHandler(onContextMenu, container)} onContextMenu={wrapHandler(onContextMenu, container)}
onWheel={wrapHandler(onWheel, container)} onWheel={wrapHandler(onWheel, container)}
onPointerEnter={hasActiveSelection ? undefined : onPaneMouseEnter} onPointerEnter={hasActiveSelection ? undefined : onPaneMouseEnter}
onPointerDown={hasActiveSelection ? onPointerDown : onPaneMouseMove} onPointerDown={hasActiveSelection ? undefined : onPaneMouseMove}
onPointerMove={hasActiveSelection ? onPointerMove : onPaneMouseMove} onPointerMove={hasActiveSelection ? onPointerMove : onPaneMouseMove}
onPointerUp={hasActiveSelection ? onPointerUp : undefined} onPointerUp={hasActiveSelection ? onPointerUp : undefined}
onPointerDownCapture={hasActiveSelection ? onPointerDown : undefined}
onMouseDownCapture={hasActiveSelection ? onMouseDownCapture : undefined}
onClickCapture={hasActiveSelection ? onClickCapture : undefined}
onPointerLeave={onPaneMouseLeave} onPointerLeave={onPaneMouseLeave}
ref={container} ref={container}
style={containerStyle} style={containerStyle}
-1
View File
@@ -43,7 +43,6 @@ export function isInputDOMNode(event: KeyboardEvent): boolean {
if (target?.nodeType !== 1 /* Node.ELEMENT_NODE */) return false; if (target?.nodeType !== 1 /* Node.ELEMENT_NODE */) return false;
const isInput = inputTags.includes(target.nodeName) || target.hasAttribute('contenteditable'); 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');
} }