전략편집기 수정
This commit is contained in:
@@ -94,7 +94,11 @@ export function findFlowNodeIdAtClientPoint(clientX: number, clientY: number): s
|
||||
for (const el of elementsUnderDragPoint(clientX, clientY)) {
|
||||
const nodeEl = el.closest('.react-flow__node') as HTMLElement | null;
|
||||
if (nodeEl) {
|
||||
const id = nodeEl.getAttribute('data-id');
|
||||
const id = nodeEl.getAttribute('data-id')
|
||||
?? nodeEl.dataset.id
|
||||
?? (nodeEl.id.startsWith('react-flow__node-')
|
||||
? nodeEl.id.slice('react-flow__node-'.length)
|
||||
: null);
|
||||
if (id) return id;
|
||||
}
|
||||
const handleEl = el.closest('[data-nodeid]') as HTMLElement | null;
|
||||
|
||||
@@ -53,6 +53,7 @@ let moveRafId: number | null = null;
|
||||
let pendingMove: { x: number; y: number } | null = null;
|
||||
let unbindActiveDrag: (() => void) | null = null;
|
||||
let pendingPointerListeners: (() => void) | null = null;
|
||||
let lastDragClientXY: { x: number; y: number } | null = null;
|
||||
|
||||
function hasCoarsePointer(): boolean {
|
||||
if (typeof window === 'undefined') return false;
|
||||
@@ -136,6 +137,7 @@ function cleanupDrag() {
|
||||
activePointerId = null;
|
||||
activeTouchId = null;
|
||||
pendingMove = null;
|
||||
lastDragClientXY = null;
|
||||
if (moveRafId != null) {
|
||||
cancelAnimationFrame(moveRafId);
|
||||
moveRafId = null;
|
||||
@@ -149,17 +151,20 @@ function cleanupDrag() {
|
||||
function finishDrag(phase: 'end' | 'cancel', xy: { x: number; y: number }) {
|
||||
if (!activePayload) return;
|
||||
const payload = activePayload;
|
||||
cleanupDrag();
|
||||
const dropXY = lastDragClientXY ?? xy;
|
||||
|
||||
if (phase === 'end') {
|
||||
suppressClickUntil = Date.now() + 400;
|
||||
dispatchEnd(xy, payload);
|
||||
dispatchEnd(dropXY, payload);
|
||||
} else {
|
||||
emit({ phase: 'cancel', x: xy.x, y: xy.y, payload });
|
||||
emit({ phase: 'cancel', x: dropXY.x, y: dropXY.y, payload });
|
||||
}
|
||||
cleanupDrag();
|
||||
}
|
||||
|
||||
export function notifyPaletteDragMove(clientX: number, clientY: number) {
|
||||
if (!activePayload) return;
|
||||
lastDragClientXY = { x: clientX, y: clientY };
|
||||
pendingMove = { x: clientX, y: clientY };
|
||||
if (moveRafId != null) return;
|
||||
moveRafId = requestAnimationFrame(() => {
|
||||
@@ -212,7 +217,7 @@ function bindActiveDragWindowListeners(pointerId: number) {
|
||||
if (!eventMatchesActiveInput(ev)) return;
|
||||
finishDrag('end', xy);
|
||||
},
|
||||
{ preventTouchScroll: true },
|
||||
{ preventTouchScroll: true, useCapture: true },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -244,6 +249,7 @@ function beginDrag(
|
||||
activePayload = payload;
|
||||
activePointerId = pointerId;
|
||||
activeTouchId = touchId;
|
||||
lastDragClientXY = { x: xy.x, y: xy.y };
|
||||
document.body.classList.add('se-palette-drag-active');
|
||||
|
||||
bindActiveDragWindowListeners(pointerId);
|
||||
|
||||
@@ -40,6 +40,8 @@ export function clientXYFromNative(e: Event): ClientXY | null {
|
||||
export interface BindWindowDragOptions {
|
||||
/** 터치 드래그 중 페이지 스크롤 방지 (기본 true) */
|
||||
preventTouchScroll?: boolean;
|
||||
/** capture 단계에서 수신 — overlay stopPropagation 우회 */
|
||||
useCapture?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,9 +53,16 @@ export function bindWindowDrag(
|
||||
onEnd: (xy: ClientXY, ev: Event) => void,
|
||||
options: BindWindowDragOptions = {},
|
||||
): () => void {
|
||||
const { preventTouchScroll = true } = options;
|
||||
const { preventTouchScroll = true, useCapture = false } = options;
|
||||
let lastXY: ClientXY = { x: 0, y: 0 };
|
||||
|
||||
const moveOpts: AddEventListenerOptions | boolean = useCapture
|
||||
? { capture: true, passive: !preventTouchScroll }
|
||||
: { passive: !preventTouchScroll };
|
||||
const endOpts: AddEventListenerOptions | boolean = useCapture
|
||||
? { capture: true }
|
||||
: false;
|
||||
|
||||
const move = (ev: Event) => {
|
||||
const xy = clientXYFromNative(ev);
|
||||
if (!xy) return;
|
||||
@@ -69,24 +78,24 @@ export function bindWindowDrag(
|
||||
onEnd(xy, ev);
|
||||
};
|
||||
|
||||
window.addEventListener('pointermove', move);
|
||||
window.addEventListener('pointerup', end);
|
||||
window.addEventListener('pointercancel', end);
|
||||
window.addEventListener('mousemove', move);
|
||||
window.addEventListener('mouseup', end);
|
||||
window.addEventListener('touchmove', move, { passive: !preventTouchScroll });
|
||||
window.addEventListener('touchend', end);
|
||||
window.addEventListener('touchcancel', end);
|
||||
window.addEventListener('pointermove', move, moveOpts);
|
||||
window.addEventListener('pointerup', end, endOpts);
|
||||
window.addEventListener('pointercancel', end, endOpts);
|
||||
window.addEventListener('mousemove', move, moveOpts);
|
||||
window.addEventListener('mouseup', end, endOpts);
|
||||
window.addEventListener('touchmove', move, moveOpts);
|
||||
window.addEventListener('touchend', end, endOpts);
|
||||
window.addEventListener('touchcancel', end, endOpts);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('pointermove', move);
|
||||
window.removeEventListener('pointerup', end);
|
||||
window.removeEventListener('pointercancel', end);
|
||||
window.removeEventListener('mousemove', move);
|
||||
window.removeEventListener('mouseup', end);
|
||||
window.removeEventListener('touchmove', move);
|
||||
window.removeEventListener('touchend', end);
|
||||
window.removeEventListener('touchcancel', end);
|
||||
window.removeEventListener('pointermove', move, moveOpts);
|
||||
window.removeEventListener('pointerup', end, endOpts);
|
||||
window.removeEventListener('pointercancel', end, endOpts);
|
||||
window.removeEventListener('mousemove', move, moveOpts);
|
||||
window.removeEventListener('mouseup', end, endOpts);
|
||||
window.removeEventListener('touchmove', move, moveOpts);
|
||||
window.removeEventListener('touchend', end, endOpts);
|
||||
window.removeEventListener('touchcancel', end, endOpts);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user