import { useSyncExternalStore } from "react"; import type { PluginStoreState, ThemeMode, Locale, } from "@edu/shared-ts/contracts"; /** * usePluginStore - Zustand 全局状态 Hook(portal-shell spec §5.2.2) * * 封装 Zustand store 的订阅,提供 theme/locale/sidebarCollapsed 状态管理。 * 此 hook 是通用封装,实际 store 实例由 portal-shell 创建并注入。 * * 设计原则(@edu/hooks):hooks 不直接依赖特定 store 实例, * 通过 subscribe/getSnapshot 与外部 store 交互。 * * 关联:portal-shell spec §5.2.2、§9.3 */ /** Store 实例接口(与 Zustand create() 返回值兼容) */ export interface PluginStoreInstance extends PluginStoreState { subscribe: (listener: () => void) => () => void; getState: () => PluginStoreState; } /** 全局 store 引用(由 portal-shell 注入) */ let globalStore: PluginStoreInstance | null = null; /** * 注入全局 PluginStore 实例(portal-shell 启动时调用) * * @example * import { usePluginStore as originalStore } from "@/shell/PluginStore"; * injectPluginStore(originalStore as PluginStoreInstance); */ export function injectPluginStore(store: PluginStoreInstance): void { globalStore = store; } /** * 读取 PluginStore 全局状态(theme/locale/sidebarCollapsed) * * @example * const { theme, setTheme } = usePluginStore(); */ export function usePluginStore(): PluginStoreState { return useSyncExternalStore( (listener) => { if (!globalStore) return () => {}; return globalStore.subscribe(listener); }, () => { if (!globalStore) { return DEFAULT_STATE; } return globalStore.getState(); }, () => DEFAULT_STATE, ); } /** 默认状态(store 未注入时使用) */ const DEFAULT_STATE: PluginStoreState = { theme: "light", setTheme: (_theme: ThemeMode) => { // store 未注入时的空操作 }, locale: "zh-CN", setLocale: (_locale: Locale) => { // store 未注入时的空操作 }, sidebarCollapsed: false, toggleSidebar: () => { // store 未注入时的空操作 }, unreadNotificationIds: [], markNotificationsRead: (_ids: string[]) => { // store 未注入时的空操作 }, };