79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
|
|
/**
|
||
|
|
* @module useSelectionState
|
||
|
|
* @description 캔버스에서 선택된 컴포넌트 상태를 관리한다.
|
||
|
|
* 단일 선택(selectedComponentId)과 다중 선택(selectedComponentIds)을 동기화하여
|
||
|
|
* 항상 일관된 선택 상태를 유지한다.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { useState, useCallback } from "react";
|
||
|
|
|
||
|
|
export interface SelectionState {
|
||
|
|
selectedComponentId: string | null;
|
||
|
|
selectedComponentIds: string[];
|
||
|
|
selectComponent: (id: string | null, isMultiSelect?: boolean) => void;
|
||
|
|
selectMultipleComponents: (ids: string[]) => void;
|
||
|
|
clearSelection: () => void;
|
||
|
|
setSelectedComponentId: React.Dispatch<React.SetStateAction<string | null>>;
|
||
|
|
setSelectedComponentIds: React.Dispatch<React.SetStateAction<string[]>>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useSelectionState(): SelectionState {
|
||
|
|
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);
|
||
|
|
const [selectedComponentIds, setSelectedComponentIds] = useState<string[]>([]);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 단일 또는 다중(Ctrl+클릭) 선택 처리.
|
||
|
|
* id가 null이면 전체 선택 해제.
|
||
|
|
*/
|
||
|
|
const selectComponent = useCallback((id: string | null, isMultiSelect = false) => {
|
||
|
|
if (id === null) {
|
||
|
|
setSelectedComponentId(null);
|
||
|
|
setSelectedComponentIds([]);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isMultiSelect) {
|
||
|
|
setSelectedComponentIds((prev) => {
|
||
|
|
if (prev.includes(id)) {
|
||
|
|
// 이미 선택된 항목 제거
|
||
|
|
const next = prev.filter((compId) => compId !== id);
|
||
|
|
setSelectedComponentId(next.length > 0 ? next[0] : null);
|
||
|
|
return next;
|
||
|
|
}
|
||
|
|
setSelectedComponentId(id);
|
||
|
|
return [...prev, id];
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
setSelectedComponentId(id);
|
||
|
|
setSelectedComponentIds([id]);
|
||
|
|
}
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
/** 마퀴(드래그) 선택 등 여러 컴포넌트를 한 번에 선택할 때 사용. */
|
||
|
|
const selectMultipleComponents = useCallback((ids: string[]) => {
|
||
|
|
if (ids.length === 0) {
|
||
|
|
setSelectedComponentId(null);
|
||
|
|
setSelectedComponentIds([]);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
setSelectedComponentId(ids[0]);
|
||
|
|
setSelectedComponentIds(ids);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
/** 선택 전체 해제 (페이지 전환 등에서 사용). */
|
||
|
|
const clearSelection = useCallback(() => {
|
||
|
|
setSelectedComponentId(null);
|
||
|
|
setSelectedComponentIds([]);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return {
|
||
|
|
selectedComponentId,
|
||
|
|
selectedComponentIds,
|
||
|
|
selectComponent,
|
||
|
|
selectMultipleComponents,
|
||
|
|
clearSelection,
|
||
|
|
setSelectedComponentId,
|
||
|
|
setSelectedComponentIds,
|
||
|
|
};
|
||
|
|
}
|