{"version":3,"file":"uiSlice.mjs","sources":["../../../../src/lib/state/slices/uiSlice.ts"],"sourcesContent":["/**\n * @file UI Slice\n * @description UI state management with atomic updates and DevTools integration\n *\n * This slice manages all UI-related state including sidebar, modals, loading states,\n * and toasts. Uses Immer for immutable updates and automatic action naming for DevTools.\n */\n\nimport { createSlice } from '../core/createSlice';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Toast notification\n */\nexport interface Toast {\n  id: string;\n  type: 'success' | 'error' | 'warning' | 'info';\n  message: string;\n  title?: string;\n  duration?: number;\n  dismissible?: boolean;\n}\n\n/**\n * Modal stack entry for nested modals\n */\nexport interface ModalStackEntry {\n  id: string;\n  data: Record<string, unknown> | null;\n}\n\n/**\n * UI state interface\n */\nexport interface UIState {\n  // Sidebar\n  sidebarOpen: boolean;\n  sidebarCollapsed: boolean;\n\n  // Modal (with stack support for nested modals)\n  activeModal: string | null;\n  modalData: Record<string, unknown> | null;\n  modalStack: ModalStackEntry[];\n\n  // Loading\n  globalLoading: boolean;\n  loadingMessage: string | null;\n  loadingProgress: number | null;\n\n  // Toasts\n  toasts: Toast[];\n\n  // Layout\n  layoutDensity: 'compact' | 'comfortable' | 'spacious';\n  animationsEnabled: boolean;\n\n  // Command Palette\n  commandPaletteOpen: boolean;\n}\n\n/**\n * UI actions interface\n */\nexport interface UIActions {\n  // Sidebar Actions\n  /** Toggle sidebar open/closed state */\n  toggleSidebar: () => void;\n  /** Set sidebar open state explicitly */\n  setSidebarOpen: (open: boolean) => void;\n  /** Set sidebar collapsed state (narrow vs full width) */\n  setSidebarCollapsed: (collapsed: boolean) => void;\n\n  // Modal Actions (with stack support for nested modals)\n  /** Open a modal by ID, optionally passing data. Supports nesting. */\n  openModal: (modalId: string, data?: Record<string, unknown>) => void;\n  /** Close current modal, returning to previous in stack if nested */\n  closeModal: () => void;\n  /** Close all modals and clear the modal stack */\n  closeAllModals: () => void;\n  /** Get data passed to current modal */\n  getModalData: <T extends Record<string, unknown>>() => T | null;\n\n  // Loading Actions\n  /** Set global loading state with optional message */\n  setGlobalLoading: (loading: boolean, message?: string) => void;\n  /** Set loading progress (0-100) or null to hide progress */\n  setLoadingProgress: (progress: number | null) => void;\n\n  // Toast Actions\n  /** Add a toast notification, returns the toast ID */\n  addToast: (toast: Omit<Toast, 'id'>) => string;\n  /** Remove a specific toast by ID */\n  removeToast: (id: string) => void;\n  /** Clear all toasts */\n  clearToasts: () => void;\n\n  // Layout Actions\n  /** Set UI density (compact, comfortable, spacious) */\n  setLayoutDensity: (density: UIState['layoutDensity']) => void;\n  /** Enable or disable UI animations */\n  setAnimationsEnabled: (enabled: boolean) => void;\n\n  // Command Palette Actions\n  /** Toggle command palette visibility */\n  toggleCommandPalette: () => void;\n  /** Set command palette open state explicitly */\n  setCommandPaletteOpen: (open: boolean) => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialUIState: UIState = {\n  // Sidebar\n  sidebarOpen: true,\n  sidebarCollapsed: false,\n\n  // Modal\n  activeModal: null,\n  modalData: null,\n  modalStack: [],\n\n  // Loading\n  globalLoading: false,\n  loadingMessage: null,\n  loadingProgress: null,\n\n  // Toasts\n  toasts: [],\n\n  // Layout\n  layoutDensity: 'comfortable',\n  animationsEnabled: true,\n\n  // Command Palette\n  commandPaletteOpen: false,\n};\n\n// ============================================================================\n// Slice Definition\n// ============================================================================\n\n/**\n * Generate unique toast ID\n */\nfunction generateToastId(): string {\n  return `toast-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * UI slice using createSlice factory for automatic DevTools action naming\n *\n * All actions are automatically prefixed with \"ui/\" in DevTools, e.g.:\n * - ui/toggleSidebar\n * - ui/openModal\n * - ui/addToast\n */\nexport const uiSlice = createSlice<\n  UIState,\n  UIActions & Record<string, (...args: never[]) => unknown>\n>({\n  name: 'ui',\n  initialState: initialUIState,\n  actions: (set, get) => ({\n    // ========================================================================\n    // Sidebar Actions\n    // ========================================================================\n\n    toggleSidebar: () => {\n      set((state) => {\n        state.sidebarOpen = !state.sidebarOpen;\n      }, 'toggleSidebar');\n    },\n\n    setSidebarOpen: (open) => {\n      set((state) => {\n        state.sidebarOpen = open;\n      }, 'setSidebarOpen');\n    },\n\n    setSidebarCollapsed: (collapsed) => {\n      set((state) => {\n        state.sidebarCollapsed = collapsed;\n      }, 'setSidebarCollapsed');\n    },\n\n    // ========================================================================\n    // Modal Actions (with stack for nested modals)\n    // ========================================================================\n\n    openModal: (modalId, data) => {\n      set((state) => {\n        // Push current modal to stack if one is active\n        if (state.activeModal !== null) {\n          state.modalStack.push({\n            id: state.activeModal,\n            data: state.modalData,\n          });\n        }\n        state.activeModal = modalId;\n        state.modalData = data ?? null;\n      }, 'openModal');\n    },\n\n    closeModal: () => {\n      set((state) => {\n        // Pop from stack if available (supports nested modals)\n        const previous = state.modalStack.pop();\n        if (previous) {\n          state.activeModal = previous.id;\n          state.modalData = previous.data;\n        } else {\n          state.activeModal = null;\n          state.modalData = null;\n        }\n      }, 'closeModal');\n    },\n\n    closeAllModals: () => {\n      set((state) => {\n        state.activeModal = null;\n        state.modalData = null;\n        state.modalStack = [];\n      }, 'closeAllModals');\n    },\n\n    getModalData: <T extends Record<string, unknown>>() => {\n      return get().modalData as T | null;\n    },\n\n    // ========================================================================\n    // Loading Actions\n    // ========================================================================\n\n    setGlobalLoading: (loading, message) => {\n      set((state) => {\n        state.globalLoading = loading;\n        state.loadingMessage = message ?? null;\n        // Reset progress when loading ends\n        if (!loading) {\n          state.loadingProgress = null;\n        }\n      }, 'setGlobalLoading');\n    },\n\n    setLoadingProgress: (progress) => {\n      set((state) => {\n        state.loadingProgress = progress;\n      }, 'setLoadingProgress');\n    },\n\n    // ========================================================================\n    // Toast Actions\n    // ========================================================================\n\n    addToast: (toast) => {\n      const id = generateToastId();\n      set((state) => {\n        state.toasts.push({\n          ...toast,\n          id,\n          dismissible: toast.dismissible ?? true,\n        });\n      }, 'addToast');\n      return id;\n    },\n\n    removeToast: (id) => {\n      set((state) => {\n        const index = state.toasts.findIndex((t) => t.id === id);\n        if (index !== -1) {\n          state.toasts.splice(index, 1);\n        }\n      }, 'removeToast');\n    },\n\n    clearToasts: () => {\n      set((state) => {\n        state.toasts = [];\n      }, 'clearToasts');\n    },\n\n    // ========================================================================\n    // Layout Actions\n    // ========================================================================\n\n    setLayoutDensity: (density) => {\n      set((state) => {\n        state.layoutDensity = density;\n      }, 'setLayoutDensity');\n    },\n\n    setAnimationsEnabled: (enabled) => {\n      set((state) => {\n        state.animationsEnabled = enabled;\n      }, 'setAnimationsEnabled');\n    },\n\n    // ========================================================================\n    // Command Palette Actions\n    // ========================================================================\n\n    toggleCommandPalette: () => {\n      set((state) => {\n        state.commandPaletteOpen = !state.commandPaletteOpen;\n      }, 'toggleCommandPalette');\n    },\n\n    setCommandPaletteOpen: (open) => {\n      set((state) => {\n        state.commandPaletteOpen = open;\n      }, 'setCommandPaletteOpen');\n    },\n  }),\n});\n\n// ============================================================================\n// Exported Type\n// ============================================================================\n\nexport type UISlice = UIState & UIActions;\n"],"names":["initialUIState","generateToastId","uiSlice","createSlice","set","get","state","open","collapsed","modalId","data","previous","loading","message","progress","toast","id","index","t","density","enabled"],"mappings":"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"}