전략 편집기 수정
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
import { elementsUnderDragPoint } from './flowScreenProjection';
|
||||
import {
|
||||
bindWindowDrag,
|
||||
clientXYFromNative,
|
||||
isPrimaryPointerButton,
|
||||
} from './pointerDrag';
|
||||
import { isDesktop } from './platform';
|
||||
@@ -47,13 +48,16 @@ let activePointerId: number | null = null;
|
||||
let activeTouchId: number | null = null;
|
||||
let overlayController: OverlayController | null = null;
|
||||
let overlayElement: HTMLElement | null = null;
|
||||
let gestureCaptureEl: HTMLElement | null = null;
|
||||
let listeners = new Set<PaletteDragListener>();
|
||||
let dropHandler: PaletteDropHandler | null = null;
|
||||
let moveRafId: number | null = null;
|
||||
let pendingMove: { x: number; y: number } | null = null;
|
||||
let unbindActiveDrag: (() => void) | null = null;
|
||||
let unbindActiveMove: (() => void) | null = null;
|
||||
let unbindActiveEnd: (() => void) | null = null;
|
||||
let pendingPointerListeners: (() => void) | null = null;
|
||||
let lastDragClientXY: { x: number; y: number } | null = null;
|
||||
let endListenersArmed = false;
|
||||
|
||||
function hasCoarsePointer(): boolean {
|
||||
if (typeof window === 'undefined') return false;
|
||||
@@ -108,6 +112,12 @@ function dispatchEnd(xy: { x: number; y: number }, payload: PaletteDragPayload)
|
||||
|
||||
function releasePointerCapture(pointerId: number | null) {
|
||||
if (pointerId == null) return;
|
||||
try {
|
||||
gestureCaptureEl?.releasePointerCapture(pointerId);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
gestureCaptureEl = null;
|
||||
try {
|
||||
overlayElement?.releasePointerCapture(pointerId);
|
||||
} catch {
|
||||
@@ -127,10 +137,17 @@ function clearPendingPointerListeners() {
|
||||
pendingPointerListeners = null;
|
||||
}
|
||||
|
||||
function unbindActiveDragListeners() {
|
||||
unbindActiveMove?.();
|
||||
unbindActiveMove = null;
|
||||
unbindActiveEnd?.();
|
||||
unbindActiveEnd = null;
|
||||
endListenersArmed = false;
|
||||
}
|
||||
|
||||
function cleanupDrag() {
|
||||
const pointerId = activePointerId;
|
||||
unbindActiveDrag?.();
|
||||
unbindActiveDrag = null;
|
||||
unbindActiveDragListeners();
|
||||
clearPendingPointerListeners();
|
||||
releasePointerCapture(pointerId);
|
||||
activePayload = null;
|
||||
@@ -177,10 +194,12 @@ export function notifyPaletteDragMove(clientX: number, clientY: number) {
|
||||
}
|
||||
|
||||
export function notifyPaletteDragEnd(clientX: number, clientY: number) {
|
||||
if (!endListenersArmed) return;
|
||||
finishDrag('end', { x: clientX, y: clientY });
|
||||
}
|
||||
|
||||
export function notifyPaletteDragCancel(clientX: number, clientY: number) {
|
||||
if (!endListenersArmed) return;
|
||||
finishDrag('cancel', { x: clientX, y: clientY });
|
||||
}
|
||||
|
||||
@@ -203,24 +222,43 @@ function eventMatchesActiveInput(ev: Event): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function bindActiveDragWindowListeners(pointerId: number) {
|
||||
unbindActiveDrag?.();
|
||||
function bindActiveDragMoveListeners(pointerId: number) {
|
||||
unbindActiveMove?.();
|
||||
|
||||
unbindActiveDrag = bindWindowDrag(
|
||||
unbindActiveMove = bindWindowDrag(
|
||||
(xy, ev) => {
|
||||
if (!activePayload || activePointerId !== pointerId) return;
|
||||
if (!eventMatchesActiveInput(ev)) return;
|
||||
notifyPaletteDragMove(xy.x, xy.y);
|
||||
},
|
||||
(xy, ev) => {
|
||||
if (!activePayload || activePointerId !== pointerId) return;
|
||||
if (!eventMatchesActiveInput(ev)) return;
|
||||
finishDrag('end', xy);
|
||||
},
|
||||
() => { /* end 는 별도 등록 */ },
|
||||
{ preventTouchScroll: true, useCapture: true },
|
||||
);
|
||||
}
|
||||
|
||||
function bindActiveDragEndListeners(pointerId: number) {
|
||||
unbindActiveEnd?.();
|
||||
|
||||
const onEnd = (ev: Event) => {
|
||||
if (!endListenersArmed) return;
|
||||
if (!activePayload || activePointerId !== pointerId) return;
|
||||
if (!eventMatchesActiveInput(ev)) return;
|
||||
const xy = clientXYFromNative(ev) ?? lastDragClientXY;
|
||||
if (!xy) return;
|
||||
finishDrag('end', xy);
|
||||
};
|
||||
|
||||
window.addEventListener('pointerup', onEnd, true);
|
||||
window.addEventListener('mouseup', onEnd, true);
|
||||
window.addEventListener('touchend', onEnd, true);
|
||||
|
||||
unbindActiveEnd = () => {
|
||||
window.removeEventListener('pointerup', onEnd, true);
|
||||
window.removeEventListener('mouseup', onEnd, true);
|
||||
window.removeEventListener('touchend', onEnd, true);
|
||||
};
|
||||
}
|
||||
|
||||
function captureOnOverlay(pointerId: number) {
|
||||
try {
|
||||
overlayElement?.setPointerCapture(pointerId);
|
||||
@@ -236,6 +274,11 @@ function captureOnOverlay(pointerId: number) {
|
||||
}
|
||||
}
|
||||
|
||||
function armDragEndListeners(pointerId: number) {
|
||||
endListenersArmed = true;
|
||||
bindActiveDragEndListeners(pointerId);
|
||||
}
|
||||
|
||||
function beginDrag(
|
||||
payload: PaletteDragPayload,
|
||||
xy: { x: number; y: number },
|
||||
@@ -250,14 +293,23 @@ function beginDrag(
|
||||
activePointerId = pointerId;
|
||||
activeTouchId = touchId;
|
||||
lastDragClientXY = { x: xy.x, y: xy.y };
|
||||
endListenersArmed = false;
|
||||
document.body.classList.add('se-palette-drag-active');
|
||||
|
||||
bindActiveDragWindowListeners(pointerId);
|
||||
bindActiveDragMoveListeners(pointerId);
|
||||
overlayController?.mount({ payload, pointerId, x: xy.x, y: xy.y });
|
||||
|
||||
requestAnimationFrame(() => captureOnOverlay(pointerId));
|
||||
|
||||
emit({ phase: 'start', x: xy.x, y: xy.y, payload });
|
||||
notifyPaletteDragMove(xy.x, xy.y);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
if (activePointerId !== pointerId) return;
|
||||
captureOnOverlay(pointerId);
|
||||
requestAnimationFrame(() => {
|
||||
if (activePointerId !== pointerId) return;
|
||||
armDragEndListeners(pointerId);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function bindPaletteDragOverlayElement(el: HTMLElement | null) {
|
||||
@@ -315,6 +367,14 @@ export function handlePalettePointerDown(
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const sourceEl = e.currentTarget as HTMLElement;
|
||||
try {
|
||||
sourceEl.setPointerCapture(e.pointerId);
|
||||
gestureCaptureEl = sourceEl;
|
||||
} catch {
|
||||
/* overlay/body capture later */
|
||||
}
|
||||
|
||||
startPaletteDragGesture(
|
||||
e.clientX,
|
||||
e.clientY,
|
||||
|
||||
Reference in New Issue
Block a user