mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-22 04:09:22 +00:00
232 lines
7.3 KiB
TypeScript
232 lines
7.3 KiB
TypeScript
/**
|
|
* ToolWorkflowContext - Manages tool selection, UI state, and workflow coordination
|
|
* Eliminates prop drilling with a single, simple context
|
|
*/
|
|
|
|
import React, { createContext, useContext, useReducer, useCallback, useMemo } from 'react';
|
|
import { useToolManagement } from '../hooks/useToolManagement';
|
|
import { type ToolRegistryEntry } from '../data/toolRegistry';
|
|
import { PageEditorFunctions } from '../types/pageEditor';
|
|
|
|
// State interface
|
|
interface ToolWorkflowState {
|
|
// UI State
|
|
sidebarsVisible: boolean;
|
|
leftPanelView: 'toolPicker' | 'toolContent';
|
|
readerMode: boolean;
|
|
|
|
// File/Preview State
|
|
previewFile: File | null;
|
|
pageEditorFunctions: PageEditorFunctions | null;
|
|
|
|
// Search State
|
|
searchQuery: string;
|
|
}
|
|
|
|
// Actions
|
|
type ToolWorkflowAction =
|
|
| { type: 'SET_SIDEBARS_VISIBLE'; payload: boolean }
|
|
| { type: 'SET_LEFT_PANEL_VIEW'; payload: 'toolPicker' | 'toolContent' }
|
|
| { type: 'SET_READER_MODE'; payload: boolean }
|
|
| { type: 'SET_PREVIEW_FILE'; payload: File | null }
|
|
| { type: 'SET_PAGE_EDITOR_FUNCTIONS'; payload: PageEditorFunctions | null }
|
|
| { type: 'SET_SEARCH_QUERY'; payload: string }
|
|
| { type: 'RESET_UI_STATE' };
|
|
|
|
// Initial state
|
|
const initialState: ToolWorkflowState = {
|
|
sidebarsVisible: true,
|
|
leftPanelView: 'toolPicker',
|
|
readerMode: false,
|
|
previewFile: null,
|
|
pageEditorFunctions: null,
|
|
searchQuery: '',
|
|
};
|
|
|
|
// Reducer
|
|
function toolWorkflowReducer(state: ToolWorkflowState, action: ToolWorkflowAction): ToolWorkflowState {
|
|
switch (action.type) {
|
|
case 'SET_SIDEBARS_VISIBLE':
|
|
return { ...state, sidebarsVisible: action.payload };
|
|
case 'SET_LEFT_PANEL_VIEW':
|
|
return { ...state, leftPanelView: action.payload };
|
|
case 'SET_READER_MODE':
|
|
return { ...state, readerMode: action.payload };
|
|
case 'SET_PREVIEW_FILE':
|
|
return { ...state, previewFile: action.payload };
|
|
case 'SET_PAGE_EDITOR_FUNCTIONS':
|
|
return { ...state, pageEditorFunctions: action.payload };
|
|
case 'SET_SEARCH_QUERY':
|
|
return { ...state, searchQuery: action.payload };
|
|
case 'RESET_UI_STATE':
|
|
return { ...initialState, searchQuery: state.searchQuery }; // Preserve search
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
|
|
// Context value interface
|
|
interface ToolWorkflowContextValue extends ToolWorkflowState {
|
|
// Tool management (from hook)
|
|
selectedToolKey: string | null;
|
|
selectedTool: ToolRegistryEntry | null;
|
|
toolRegistry: Record<string, ToolRegistryEntry>; // From useToolManagement
|
|
|
|
// UI Actions
|
|
setSidebarsVisible: (visible: boolean) => void;
|
|
setLeftPanelView: (view: 'toolPicker' | 'toolContent') => void;
|
|
setReaderMode: (mode: boolean) => void;
|
|
setPreviewFile: (file: File | null) => void;
|
|
setPageEditorFunctions: (functions: PageEditorFunctions | null) => void;
|
|
setSearchQuery: (query: string) => void;
|
|
|
|
// Tool Actions
|
|
selectTool: (toolId: string) => void;
|
|
clearToolSelection: () => void;
|
|
|
|
// Workflow Actions (compound actions)
|
|
handleToolSelect: (toolId: string) => void;
|
|
handleBackToTools: () => void;
|
|
handleReaderToggle: () => void;
|
|
|
|
// Computed values
|
|
filteredTools: [string, ToolRegistryEntry][]; // Filtered by search
|
|
isPanelVisible: boolean;
|
|
}
|
|
|
|
const ToolWorkflowContext = createContext<ToolWorkflowContextValue | undefined>(undefined);
|
|
|
|
// Provider component
|
|
interface ToolWorkflowProviderProps {
|
|
children: React.ReactNode;
|
|
/** Handler for view changes (passed from parent) */
|
|
onViewChange?: (view: string) => void;
|
|
}
|
|
|
|
export function ToolWorkflowProvider({ children, onViewChange }: ToolWorkflowProviderProps) {
|
|
const [state, dispatch] = useReducer(toolWorkflowReducer, initialState);
|
|
|
|
// Tool management hook
|
|
const {
|
|
selectedToolKey,
|
|
selectedTool,
|
|
toolRegistry,
|
|
selectTool,
|
|
clearToolSelection,
|
|
} = useToolManagement();
|
|
|
|
// UI Action creators
|
|
const setSidebarsVisible = useCallback((visible: boolean) => {
|
|
dispatch({ type: 'SET_SIDEBARS_VISIBLE', payload: visible });
|
|
}, []);
|
|
|
|
const setLeftPanelView = useCallback((view: 'toolPicker' | 'toolContent') => {
|
|
dispatch({ type: 'SET_LEFT_PANEL_VIEW', payload: view });
|
|
}, []);
|
|
|
|
const setReaderMode = useCallback((mode: boolean) => {
|
|
dispatch({ type: 'SET_READER_MODE', payload: mode });
|
|
}, []);
|
|
|
|
const setPreviewFile = useCallback((file: File | null) => {
|
|
dispatch({ type: 'SET_PREVIEW_FILE', payload: file });
|
|
}, []);
|
|
|
|
const setPageEditorFunctions = useCallback((functions: PageEditorFunctions | null) => {
|
|
dispatch({ type: 'SET_PAGE_EDITOR_FUNCTIONS', payload: functions });
|
|
}, []);
|
|
|
|
const setSearchQuery = useCallback((query: string) => {
|
|
dispatch({ type: 'SET_SEARCH_QUERY', payload: query });
|
|
}, []);
|
|
|
|
// Workflow actions (compound actions that coordinate multiple state changes)
|
|
const handleToolSelect = useCallback((toolId: string) => {
|
|
// Special-case: if tool is a dedicated reader tool, enter reader mode and do not go to toolContent
|
|
if (toolId === 'read' || toolId === 'view-pdf') {
|
|
setReaderMode(true);
|
|
setLeftPanelView('toolPicker');
|
|
clearToolSelection();
|
|
setSearchQuery('');
|
|
return;
|
|
}
|
|
|
|
selectTool(toolId);
|
|
onViewChange?.('fileEditor');
|
|
setLeftPanelView('toolContent');
|
|
setReaderMode(false);
|
|
// Clear search so the tool content becomes visible immediately
|
|
setSearchQuery('');
|
|
}, [selectTool, onViewChange, setLeftPanelView, setReaderMode, setSearchQuery, clearToolSelection]);
|
|
|
|
const handleBackToTools = useCallback(() => {
|
|
setLeftPanelView('toolPicker');
|
|
setReaderMode(false);
|
|
clearToolSelection();
|
|
}, [setLeftPanelView, setReaderMode, clearToolSelection]);
|
|
|
|
const handleReaderToggle = useCallback(() => {
|
|
setReaderMode(true);
|
|
}, [setReaderMode]);
|
|
|
|
// Filter tools based on search query
|
|
const filteredTools = useMemo(() => {
|
|
if (!toolRegistry) return [];
|
|
return Object.entries(toolRegistry).filter(([_, { name }]) =>
|
|
name.toLowerCase().includes(state.searchQuery.toLowerCase())
|
|
);
|
|
}, [toolRegistry, state.searchQuery]);
|
|
|
|
const isPanelVisible = useMemo(() =>
|
|
state.sidebarsVisible && !state.readerMode,
|
|
[state.sidebarsVisible, state.readerMode]
|
|
);
|
|
|
|
// Simple context value with basic memoization
|
|
const contextValue = useMemo((): ToolWorkflowContextValue => ({
|
|
// State
|
|
...state,
|
|
selectedToolKey,
|
|
selectedTool,
|
|
toolRegistry,
|
|
|
|
// Actions
|
|
setSidebarsVisible,
|
|
setLeftPanelView,
|
|
setReaderMode,
|
|
setPreviewFile,
|
|
setPageEditorFunctions,
|
|
setSearchQuery,
|
|
selectTool,
|
|
clearToolSelection,
|
|
|
|
// Workflow Actions
|
|
handleToolSelect,
|
|
handleBackToTools,
|
|
handleReaderToggle,
|
|
|
|
// Computed
|
|
filteredTools,
|
|
isPanelVisible,
|
|
}), [state, selectedToolKey, selectedTool, toolRegistry, filteredTools, isPanelVisible]);
|
|
|
|
return (
|
|
<ToolWorkflowContext.Provider value={contextValue}>
|
|
{children}
|
|
</ToolWorkflowContext.Provider>
|
|
);
|
|
}
|
|
|
|
// Custom hook to use the context
|
|
export function useToolWorkflow(): ToolWorkflowContextValue {
|
|
const context = useContext(ToolWorkflowContext);
|
|
if (!context) {
|
|
throw new Error('useToolWorkflow must be used within a ToolWorkflowProvider');
|
|
}
|
|
return context;
|
|
}
|
|
|
|
// Convenience exports for specific use cases (optional - components can use useToolWorkflow directly)
|
|
export const useToolSelection = useToolWorkflow;
|
|
export const useToolPanelState = useToolWorkflow;
|
|
export const useWorkbenchState = useToolWorkflow; |