This commit is contained in:
Macbook
2026-06-14 23:39:51 +09:00
parent b2788ee629
commit 0045f0ef2d
6 changed files with 221 additions and 70 deletions
@@ -141,6 +141,7 @@ import {
strategyDtoToListExportItem,
} from '../utils/strategyImportExport';
import PaletteChip from './strategyEditor/PaletteChip';
import PaletteDragOverlay from './strategyEditor/PaletteDragOverlay';
import SePanelCollapseHandle from './strategyEditor/SePanelCollapseHandle';
import {
clampPanelSize,
@@ -1616,6 +1617,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
return (
<div className={`se-page se-page--${theme}`}>
<PaletteDragOverlay />
{saveToast && (
<div className="se-save-toast"> DB에 .</div>
)}
@@ -0,0 +1,89 @@
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import {
bindPaletteDragOverlayElement,
notifyPaletteDragCancel,
notifyPaletteDragEnd,
notifyPaletteDragMove,
registerPaletteDragOverlay,
type PaletteDragOverlaySession,
} from '../../utils/paletteDragSession';
/**
* Tauri WebView — 드래그 중 전체 화면 overlay 가 pointer 이벤트·drop 을 수신
*/
export default function PaletteDragOverlay() {
const [session, setSession] = useState<PaletteDragOverlaySession | null>(null);
const [cursor, setCursor] = useState({ x: 0, y: 0 });
const overlayRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
registerPaletteDragOverlay({
mount: next => {
setCursor({ x: next.x, y: next.y });
setSession(next);
},
unmount: () => setSession(null),
bindElement: el => {
overlayRef.current = el as HTMLDivElement | null;
},
});
return () => registerPaletteDragOverlay(null);
}, []);
useLayoutEffect(() => {
bindPaletteDragOverlayElement(overlayRef.current);
return () => bindPaletteDragOverlayElement(null);
}, [session]);
useLayoutEffect(() => {
if (!session || !overlayRef.current) return;
try {
overlayRef.current.setPointerCapture(session.pointerId);
} catch {
/* body capture fallback */
}
}, [session]);
const onPointerMove = useCallback((e: React.PointerEvent) => {
if (!session || e.pointerId !== session.pointerId) return;
e.preventDefault();
e.stopPropagation();
setCursor({ x: e.clientX, y: e.clientY });
notifyPaletteDragMove(e.clientX, e.clientY);
}, [session]);
const onPointerUp = useCallback((e: React.PointerEvent) => {
if (!session || e.pointerId !== session.pointerId) return;
e.preventDefault();
e.stopPropagation();
notifyPaletteDragEnd(e.clientX, e.clientY);
}, [session]);
const onPointerCancel = useCallback((e: React.PointerEvent) => {
if (!session || e.pointerId !== session.pointerId) return;
e.preventDefault();
e.stopPropagation();
notifyPaletteDragCancel(e.clientX, e.clientY);
}, [session]);
if (!session) return null;
return createPortal(
<div
ref={overlayRef}
className="se-palette-drag-overlay"
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerCancel={onPointerCancel}
>
<div
className="se-palette-drag-overlay-label"
style={{ left: cursor.x, top: cursor.y }}
>
{session.payload.label}
</div>
</div>,
document.body,
);
}
@@ -1233,9 +1233,9 @@ function StrategyEditorCanvasInner({
clientX: number,
clientY: number,
) => {
if (!isOverStrategyBuilder(clientX, clientY)) return;
const { flowPos, anchorId } = resolveDropFromClient(clientX, clientY);
const overCanvas = isOverStrategyBuilder(clientX, clientY);
if (!overCanvas && !anchorId) return;
if (data.type === 'start') {
addStartAt(flowPos);
return;