/** * 캔버스 분할선 글로벌 스토어 * * 성능 최적화: 이중 리스너 구조 * - React 리스너 (subscribe): 구조적 변경만 알림 (active, isDragging 시작/종료) * - DOM 리스너 (subscribeDom): 드래그 중 위치 변경 알림 (React 우회, 직접 DOM 조작) */ export interface CanvasSplitState { initialDividerX: number; currentDividerX: number; canvasWidth: number; isDragging: boolean; active: boolean; scopeId: string; } const initialState: CanvasSplitState = { initialDividerX: 0, currentDividerX: 0, canvasWidth: 0, isDragging: false, active: false, scopeId: "", }; let state: CanvasSplitState = { ...initialState }; // React 리렌더링을 트리거하는 리스너 (구조적 변경 전용) const reactListeners = new Set<() => void>(); // DOM 직접 조작용 리스너 (드래그 중 위치 업데이트, React 우회) const domListeners = new Set<(state: CanvasSplitState) => void>(); // React용 스냅샷 (드래그 중 위치 변경에는 갱신 안 함) let reactSnapshot: CanvasSplitState = { ...initialState }; export function setCanvasSplit(updates: Partial): void { state = { ...state, ...updates }; // 드래그 중 위치만 변경 → DOM 리스너만 호출 (React 리렌더 없음) const isPositionOnlyDuringDrag = state.isDragging && Object.keys(updates).length === 1 && "currentDividerX" in updates; if (isPositionOnlyDuringDrag) { domListeners.forEach((fn) => fn(state)); return; } // 구조적 변경 → React 리스너 + DOM 리스너 모두 호출 reactSnapshot = { ...state }; reactListeners.forEach((fn) => fn()); domListeners.forEach((fn) => fn(state)); } export function resetCanvasSplit(): void { state = { ...initialState }; reactSnapshot = { ...initialState }; reactListeners.forEach((fn) => fn()); domListeners.forEach((fn) => fn(state)); } // React용: useSyncExternalStore에 연결 export function subscribe(callback: () => void): () => void { reactListeners.add(callback); return () => { reactListeners.delete(callback); }; } export function getSnapshot(): CanvasSplitState { return reactSnapshot; } export function getServerSnapshot(): CanvasSplitState { return { ...initialState }; } // DOM 직접 조작용: 드래그 중 매 프레임 위치 업데이트 수신 export function subscribeDom( callback: (state: CanvasSplitState) => void, ): () => void { domListeners.add(callback); return () => { domListeners.delete(callback); }; } // 현재 상태 직접 참조 (DOM 리스너 콜백 외부에서 최신 상태 필요 시) export function getCurrentState(): CanvasSplitState { return state; }