147 lines
3.3 KiB
TypeScript
147 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import React, {
|
|
createContext,
|
|
useContext,
|
|
useState,
|
|
useCallback,
|
|
ReactNode,
|
|
} from "react";
|
|
|
|
/**
|
|
* 활성 탭 정보
|
|
*/
|
|
export interface ActiveTabInfo {
|
|
tabId: string; // 탭 고유 ID
|
|
tabsComponentId: string; // 부모 탭 컴포넌트 ID
|
|
screenId?: number; // 탭에 연결된 화면 ID
|
|
label?: string; // 탭 라벨
|
|
}
|
|
|
|
/**
|
|
* Context 값 타입
|
|
*/
|
|
interface ActiveTabContextValue {
|
|
// 현재 활성 탭 정보 (탭 컴포넌트 ID -> 활성 탭 정보)
|
|
activeTabs: Map<string, ActiveTabInfo>;
|
|
|
|
// 활성 탭 설정
|
|
setActiveTab: (tabsComponentId: string, tabInfo: ActiveTabInfo) => void;
|
|
|
|
// 활성 탭 조회
|
|
getActiveTab: (tabsComponentId: string) => ActiveTabInfo | undefined;
|
|
|
|
// 특정 탭 컴포넌트의 활성 탭 ID 조회
|
|
getActiveTabId: (tabsComponentId: string) => string | undefined;
|
|
|
|
// 전체 활성 탭 ID 목록 (모든 탭 컴포넌트에서)
|
|
getAllActiveTabIds: () => string[];
|
|
|
|
// 탭 컴포넌트 제거 시 정리
|
|
removeTabsComponent: (tabsComponentId: string) => void;
|
|
}
|
|
|
|
const ActiveTabContext = createContext<ActiveTabContextValue | undefined>(undefined);
|
|
|
|
export const ActiveTabProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
|
const [activeTabs, setActiveTabs] = useState<Map<string, ActiveTabInfo>>(new Map());
|
|
|
|
/**
|
|
* 활성 탭 설정
|
|
*/
|
|
const setActiveTab = useCallback((tabsComponentId: string, tabInfo: ActiveTabInfo) => {
|
|
setActiveTabs((prev) => {
|
|
const newMap = new Map(prev);
|
|
newMap.set(tabsComponentId, tabInfo);
|
|
return newMap;
|
|
});
|
|
}, []);
|
|
|
|
/**
|
|
* 활성 탭 조회
|
|
*/
|
|
const getActiveTab = useCallback(
|
|
(tabsComponentId: string) => {
|
|
return activeTabs.get(tabsComponentId);
|
|
},
|
|
[activeTabs]
|
|
);
|
|
|
|
/**
|
|
* 특정 탭 컴포넌트의 활성 탭 ID 조회
|
|
*/
|
|
const getActiveTabId = useCallback(
|
|
(tabsComponentId: string) => {
|
|
return activeTabs.get(tabsComponentId)?.tabId;
|
|
},
|
|
[activeTabs]
|
|
);
|
|
|
|
/**
|
|
* 전체 활성 탭 ID 목록
|
|
*/
|
|
const getAllActiveTabIds = useCallback(() => {
|
|
return Array.from(activeTabs.values()).map((info) => info.tabId);
|
|
}, [activeTabs]);
|
|
|
|
/**
|
|
* 탭 컴포넌트 제거 시 정리
|
|
*/
|
|
const removeTabsComponent = useCallback((tabsComponentId: string) => {
|
|
setActiveTabs((prev) => {
|
|
const newMap = new Map(prev);
|
|
newMap.delete(tabsComponentId);
|
|
return newMap;
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<ActiveTabContext.Provider
|
|
value={{
|
|
activeTabs,
|
|
setActiveTab,
|
|
getActiveTab,
|
|
getActiveTabId,
|
|
getAllActiveTabIds,
|
|
removeTabsComponent,
|
|
}}
|
|
>
|
|
{children}
|
|
</ActiveTabContext.Provider>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Context Hook
|
|
*/
|
|
export const useActiveTab = () => {
|
|
const context = useContext(ActiveTabContext);
|
|
if (!context) {
|
|
// Context가 없으면 기본값 반환 (탭이 없는 화면에서 사용 시)
|
|
return {
|
|
activeTabs: new Map(),
|
|
setActiveTab: () => {},
|
|
getActiveTab: () => undefined,
|
|
getActiveTabId: () => undefined,
|
|
getAllActiveTabIds: () => [],
|
|
removeTabsComponent: () => {},
|
|
};
|
|
}
|
|
return context;
|
|
};
|
|
|
|
/**
|
|
* Optional Context Hook (에러 없이 undefined 반환)
|
|
*/
|
|
export const useActiveTabOptional = () => {
|
|
return useContext(ActiveTabContext);
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|