Stirling-PDF/frontend/src/contexts/FileSelectionContext.tsx
ConnorYoh 4c17c520d7
V2 results flow (#4196)
Better tool flow for reusability
Pinning 
Styling of tool flow
consumption of files after tooling

---------

Co-authored-by: Connor Yoh <connor@stirlingpdf.com>
Co-authored-by: James Brunton <jbrunton96@gmail.com>
2025-08-15 14:43:30 +01:00

101 lines
4.0 KiB
TypeScript

import React, { createContext, useContext, useState, useCallback, useEffect, ReactNode } from 'react';
import {
MaxFiles,
FileSelectionContextValue
} from '../types/tool';
import { useFileContext } from './FileContext';
interface FileSelectionProviderProps {
children: ReactNode;
}
const FileSelectionContext = createContext<FileSelectionContextValue | undefined>(undefined);
export function FileSelectionProvider({ children }: FileSelectionProviderProps) {
const { activeFiles } = useFileContext();
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const [maxFiles, setMaxFiles] = useState<MaxFiles>(-1);
const [isToolMode, setIsToolMode] = useState<boolean>(false);
// Sync selected files with active files - remove any selected files that are no longer active
useEffect(() => {
if (selectedFiles.length > 0) {
const activeFileSet = new Set(activeFiles);
const validSelectedFiles = selectedFiles.filter(file => activeFileSet.has(file));
if (validSelectedFiles.length !== selectedFiles.length) {
setSelectedFiles(validSelectedFiles);
}
}
}, [activeFiles, selectedFiles]);
const clearSelection = useCallback(() => {
setSelectedFiles([]);
}, []);
const selectionCount = selectedFiles.length;
const canSelectMore = maxFiles === -1 || selectionCount < maxFiles;
const isAtLimit = maxFiles > 0 && selectionCount >= maxFiles;
const isMultiFileMode = maxFiles !== 1;
const contextValue: FileSelectionContextValue = {
selectedFiles,
maxFiles,
isToolMode,
setSelectedFiles,
setMaxFiles,
setIsToolMode,
clearSelection,
canSelectMore,
isAtLimit,
selectionCount,
isMultiFileMode
};
return (
<FileSelectionContext.Provider value={contextValue}>
{children}
</FileSelectionContext.Provider>
);
}
/**
* Access the file selection context.
* Throws if used outside a <FileSelectionProvider>.
*/
export function useFileSelection(): FileSelectionContextValue {
const context = useContext(FileSelectionContext);
if (!context) {
throw new Error('useFileSelection must be used within a FileSelectionProvider');
}
return context;
}
// Returns only the file selection values relevant for tools (e.g. merge, split, etc.)
// Use this in tool panels/components that need to know which files are selected and selection limits.
export function useToolFileSelection(): Pick<FileSelectionContextValue, 'selectedFiles' | 'maxFiles' | 'canSelectMore' | 'isAtLimit' | 'selectionCount'> {
const { selectedFiles, maxFiles, canSelectMore, isAtLimit, selectionCount } = useFileSelection();
return { selectedFiles, maxFiles, canSelectMore, isAtLimit, selectionCount };
}
// Returns actions for manipulating file selection state.
// Use this in components that need to update the selection, clear it, or change selection mode.
export function useFileSelectionActions(): Pick<FileSelectionContextValue, 'setSelectedFiles' | 'clearSelection' | 'setMaxFiles' | 'setIsToolMode'> {
const { setSelectedFiles, clearSelection, setMaxFiles, setIsToolMode } = useFileSelection();
return { setSelectedFiles, clearSelection, setMaxFiles, setIsToolMode };
}
// Returns the raw file selection state (selected files, max files, tool mode).
// Use this for low-level state access, e.g. in context-aware UI.
export function useFileSelectionState(): Pick<FileSelectionContextValue, 'selectedFiles' | 'maxFiles' | 'isToolMode'> {
const { selectedFiles, maxFiles, isToolMode } = useFileSelection();
return { selectedFiles, maxFiles, isToolMode };
}
// Returns computed values derived from file selection state.
// Use this for file selection UI logic (e.g. disabling buttons when at limit).
export function useFileSelectionComputed(): Pick<FileSelectionContextValue, 'canSelectMore' | 'isAtLimit' | 'selectionCount' | 'isMultiFileMode'> {
const { canSelectMore, isAtLimit, selectionCount, isMultiFileMode } = useFileSelection();
return { canSelectMore, isAtLimit, selectionCount, isMultiFileMode };
}