mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-09-26 17:52:59 +02:00
Refactor to use MutableRefObject instead of RefObject
Replaces all instances of React.RefObject with React.MutableRefObject for refs that are mutated directly throughout the codebase. This change clarifies intent and improves type safety for refs that are updated outside of React's ref assignment.
This commit is contained in:
parent
3fa0535246
commit
57b2fcaf2c
@ -23,7 +23,7 @@ interface PageThumbnailProps {
|
|||||||
selectionMode: boolean;
|
selectionMode: boolean;
|
||||||
movingPage: number | null;
|
movingPage: number | null;
|
||||||
isAnimating: boolean;
|
isAnimating: boolean;
|
||||||
pageRefs: React.RefObject<Map<string, HTMLDivElement>>;
|
pageRefs: React.MutableRefObject<Map<string, HTMLDivElement>>;
|
||||||
onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void;
|
onReorderPages: (sourcePageNumber: number, targetIndex: number, selectedPageIds?: string[]) => void;
|
||||||
onTogglePage: (pageId: string) => void;
|
onTogglePage: (pageId: string) => void;
|
||||||
onAnimateReorder: () => void;
|
onAnimateReorder: () => void;
|
||||||
|
@ -71,7 +71,7 @@ const ToolPicker = ({ selectedToolKey, onSelect, filteredTools, isSearching = fa
|
|||||||
[visibleSections]
|
[visibleSections]
|
||||||
);
|
);
|
||||||
|
|
||||||
const scrollTo = (ref: React.RefObject<HTMLDivElement | null>) => {
|
const scrollTo = (ref: React.MutableRefObject<HTMLDivElement | null>) => {
|
||||||
const container = scrollableRef.current;
|
const container = scrollableRef.current;
|
||||||
const target = ref.current;
|
const target = ref.current;
|
||||||
if (container && target) {
|
if (container && target) {
|
||||||
|
@ -13,7 +13,7 @@ interface FileManagerContextValue {
|
|||||||
searchTerm: string;
|
searchTerm: string;
|
||||||
selectedFiles: StirlingFileStub[];
|
selectedFiles: StirlingFileStub[];
|
||||||
filteredFiles: StirlingFileStub[];
|
filteredFiles: StirlingFileStub[];
|
||||||
fileInputRef: React.RefObject<HTMLInputElement | null>;
|
fileInputRef: React.MutableRefObject<HTMLInputElement | null>;
|
||||||
selectedFilesSet: Set<FileId>;
|
selectedFilesSet: Set<FileId>;
|
||||||
expandedFileIds: Set<FileId>;
|
expandedFileIds: Set<FileId>;
|
||||||
fileGroups: Map<FileId, StirlingFileStub[]>;
|
fileGroups: Map<FileId, StirlingFileStub[]>;
|
||||||
|
@ -165,8 +165,8 @@ interface AddFileOptions {
|
|||||||
*/
|
*/
|
||||||
export async function addFiles(
|
export async function addFiles(
|
||||||
options: AddFileOptions,
|
options: AddFileOptions,
|
||||||
stateRef: React.RefObject<FileContextState>,
|
stateRef: React.MutableRefObject<FileContextState>,
|
||||||
filesRef: React.RefObject<Map<FileId, File>>,
|
filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
dispatch: React.Dispatch<FileContextAction>,
|
dispatch: React.Dispatch<FileContextAction>,
|
||||||
lifecycleManager: FileLifecycleManager,
|
lifecycleManager: FileLifecycleManager,
|
||||||
enablePersistence: boolean = false
|
enablePersistence: boolean = false
|
||||||
@ -278,7 +278,7 @@ export async function consumeFiles(
|
|||||||
inputFileIds: FileId[],
|
inputFileIds: FileId[],
|
||||||
outputStirlingFiles: StirlingFile[],
|
outputStirlingFiles: StirlingFile[],
|
||||||
outputStirlingFileStubs: StirlingFileStub[],
|
outputStirlingFileStubs: StirlingFileStub[],
|
||||||
filesRef: React.RefObject<Map<FileId, File>>,
|
filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
dispatch: React.Dispatch<FileContextAction>
|
dispatch: React.Dispatch<FileContextAction>
|
||||||
): Promise<FileId[]> {
|
): Promise<FileId[]> {
|
||||||
if (DEBUG) console.log(`📄 consumeFiles: Processing ${inputFileIds.length} input files, ${outputStirlingFiles.length} output files with pre-created stubs`);
|
if (DEBUG) console.log(`📄 consumeFiles: Processing ${inputFileIds.length} input files, ${outputStirlingFiles.length} output files with pre-created stubs`);
|
||||||
@ -357,7 +357,7 @@ export async function consumeFiles(
|
|||||||
async function restoreFilesAndCleanup(
|
async function restoreFilesAndCleanup(
|
||||||
filesToRestore: { file: File; record: StirlingFileStub }[],
|
filesToRestore: { file: File; record: StirlingFileStub }[],
|
||||||
fileIdsToRemove: FileId[],
|
fileIdsToRemove: FileId[],
|
||||||
filesRef: React.RefObject<Map<FileId, File>>,
|
filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
indexedDB?: { deleteFile: (fileId: FileId) => Promise<void> } | null
|
indexedDB?: { deleteFile: (fileId: FileId) => Promise<void> } | null
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Remove files from filesRef
|
// Remove files from filesRef
|
||||||
@ -406,7 +406,7 @@ export async function undoConsumeFiles(
|
|||||||
inputFiles: File[],
|
inputFiles: File[],
|
||||||
inputStirlingFileStubs: StirlingFileStub[],
|
inputStirlingFileStubs: StirlingFileStub[],
|
||||||
outputFileIds: FileId[],
|
outputFileIds: FileId[],
|
||||||
filesRef: React.RefObject<Map<FileId, File>>,
|
filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
dispatch: React.Dispatch<FileContextAction>,
|
dispatch: React.Dispatch<FileContextAction>,
|
||||||
indexedDB?: { saveFile: (file: File, fileId: FileId, existingThumbnail?: string) => Promise<any>; deleteFile: (fileId: FileId) => Promise<void> } | null
|
indexedDB?: { saveFile: (file: File, fileId: FileId, existingThumbnail?: string) => Promise<any>; deleteFile: (fileId: FileId) => Promise<void> } | null
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@ -468,8 +468,8 @@ export async function undoConsumeFiles(
|
|||||||
export async function addStirlingFileStubs(
|
export async function addStirlingFileStubs(
|
||||||
stirlingFileStubs: StirlingFileStub[],
|
stirlingFileStubs: StirlingFileStub[],
|
||||||
options: { insertAfterPageId?: string; selectFiles?: boolean } = {},
|
options: { insertAfterPageId?: string; selectFiles?: boolean } = {},
|
||||||
stateRef: React.RefObject<FileContextState>,
|
stateRef: React.MutableRefObject<FileContextState>,
|
||||||
filesRef: React.RefObject<Map<FileId, File>>,
|
filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
dispatch: React.Dispatch<FileContextAction>,
|
dispatch: React.Dispatch<FileContextAction>,
|
||||||
_lifecycleManager: FileLifecycleManager
|
_lifecycleManager: FileLifecycleManager
|
||||||
): Promise<StirlingFile[]> {
|
): Promise<StirlingFile[]> {
|
||||||
|
@ -15,8 +15,8 @@ import {
|
|||||||
* Create stable selectors using stateRef and filesRef
|
* Create stable selectors using stateRef and filesRef
|
||||||
*/
|
*/
|
||||||
export function createFileSelectors(
|
export function createFileSelectors(
|
||||||
stateRef: React.RefObject<FileContextState>,
|
stateRef: React.MutableRefObject<FileContextState>,
|
||||||
filesRef: React.RefObject<Map<FileId, File>>
|
filesRef: React.MutableRefObject<Map<FileId, File>>
|
||||||
): FileContextSelectors {
|
): FileContextSelectors {
|
||||||
return {
|
return {
|
||||||
getFile: (id: FileId) => {
|
getFile: (id: FileId) => {
|
||||||
@ -125,8 +125,8 @@ export function buildQuickKeySetFromMetadata(metadata: { name: string; size: num
|
|||||||
* Get primary file (first in list) - commonly used pattern
|
* Get primary file (first in list) - commonly used pattern
|
||||||
*/
|
*/
|
||||||
export function getPrimaryFile(
|
export function getPrimaryFile(
|
||||||
stateRef: React.RefObject<FileContextState>,
|
stateRef: React.MutableRefObject<FileContextState>,
|
||||||
filesRef: React.RefObject<Map<FileId, File>>
|
filesRef: React.MutableRefObject<Map<FileId, File>>
|
||||||
): { file?: File; record?: StirlingFileStub } {
|
): { file?: File; record?: StirlingFileStub } {
|
||||||
const primaryFileId = stateRef.current.files.ids[0];
|
const primaryFileId = stateRef.current.files.ids[0];
|
||||||
if (!primaryFileId) return {};
|
if (!primaryFileId) return {};
|
||||||
|
@ -16,7 +16,7 @@ export class FileLifecycleManager {
|
|||||||
private fileGenerations = new Map<string, number>(); // Generation tokens to prevent stale cleanup
|
private fileGenerations = new Map<string, number>(); // Generation tokens to prevent stale cleanup
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private filesRef: React.RefObject<Map<FileId, File>>,
|
private filesRef: React.MutableRefObject<Map<FileId, File>>,
|
||||||
private dispatch: React.Dispatch<FileContextAction>
|
private dispatch: React.Dispatch<FileContextAction>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export class FileLifecycleManager {
|
|||||||
/**
|
/**
|
||||||
* Clean up resources for a specific file (with stateRef access for complete cleanup)
|
* Clean up resources for a specific file (with stateRef access for complete cleanup)
|
||||||
*/
|
*/
|
||||||
cleanupFile = (fileId: FileId, stateRef?: React.RefObject<any>): void => {
|
cleanupFile = (fileId: FileId, stateRef?: React.MutableRefObject<any>): void => {
|
||||||
// Use comprehensive cleanup (same as removeFiles)
|
// Use comprehensive cleanup (same as removeFiles)
|
||||||
this.cleanupAllResourcesForFile(fileId, stateRef);
|
this.cleanupAllResourcesForFile(fileId, stateRef);
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ export class FileLifecycleManager {
|
|||||||
/**
|
/**
|
||||||
* Schedule delayed cleanup for a file with generation token to prevent stale cleanup
|
* Schedule delayed cleanup for a file with generation token to prevent stale cleanup
|
||||||
*/
|
*/
|
||||||
scheduleCleanup = (fileId: FileId, delay: number = 30000, stateRef?: React.RefObject<any>): void => {
|
scheduleCleanup = (fileId: FileId, delay: number = 30000, stateRef?: React.MutableRefObject<any>): void => {
|
||||||
// Cancel existing timer
|
// Cancel existing timer
|
||||||
const existingTimer = this.cleanupTimers.get(fileId);
|
const existingTimer = this.cleanupTimers.get(fileId);
|
||||||
if (existingTimer) {
|
if (existingTimer) {
|
||||||
@ -101,7 +101,7 @@ export class FileLifecycleManager {
|
|||||||
/**
|
/**
|
||||||
* Remove a file immediately with complete resource cleanup
|
* Remove a file immediately with complete resource cleanup
|
||||||
*/
|
*/
|
||||||
removeFiles = (fileIds: FileId[], stateRef?: React.RefObject<any>): void => {
|
removeFiles = (fileIds: FileId[], stateRef?: React.MutableRefObject<any>): void => {
|
||||||
fileIds.forEach(fileId => {
|
fileIds.forEach(fileId => {
|
||||||
// Clean up all resources for this file
|
// Clean up all resources for this file
|
||||||
this.cleanupAllResourcesForFile(fileId, stateRef);
|
this.cleanupAllResourcesForFile(fileId, stateRef);
|
||||||
@ -114,7 +114,7 @@ export class FileLifecycleManager {
|
|||||||
/**
|
/**
|
||||||
* Complete resource cleanup for a single file
|
* Complete resource cleanup for a single file
|
||||||
*/
|
*/
|
||||||
private cleanupAllResourcesForFile = (fileId: FileId, stateRef?: React.RefObject<any>): void => {
|
private cleanupAllResourcesForFile = (fileId: FileId, stateRef?: React.MutableRefObject<any>): void => {
|
||||||
// Remove from files ref
|
// Remove from files ref
|
||||||
this.filesRef.current.delete(fileId);
|
this.filesRef.current.delete(fileId);
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ export class FileLifecycleManager {
|
|||||||
/**
|
/**
|
||||||
* Update file record with race condition guards
|
* Update file record with race condition guards
|
||||||
*/
|
*/
|
||||||
updateStirlingFileStub = (fileId: FileId, updates: Partial<StirlingFileStub>, stateRef?: React.RefObject<any>): void => {
|
updateStirlingFileStub = (fileId: FileId, updates: Partial<StirlingFileStub>, stateRef?: React.MutableRefObject<any>): void => {
|
||||||
// Guard against updating removed files (race condition protection)
|
// Guard against updating removed files (race condition protection)
|
||||||
if (!this.filesRef.current.has(fileId)) {
|
if (!this.filesRef.current.has(fileId)) {
|
||||||
if (DEBUG) console.warn(`🗂️ Attempted to update removed file (filesRef): ${fileId}`);
|
if (DEBUG) console.warn(`🗂️ Attempted to update removed file (filesRef): ${fileId}`);
|
||||||
|
@ -32,7 +32,7 @@ import * as React from 'react';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export const useIsOverflowing = (ref: React.RefObject<HTMLElement | null>, callback?: (isOverflow: boolean) => void) => {
|
export const useIsOverflowing = (ref: React.MutableRefObject<HTMLElement | null>, callback?: (isOverflow: boolean) => void) => {
|
||||||
// State to track overflow status
|
// State to track overflow status
|
||||||
const [isOverflow, setIsOverflow] = React.useState<boolean | undefined>(undefined);
|
const [isOverflow, setIsOverflow] = React.useState<boolean | undefined>(undefined);
|
||||||
|
|
||||||
|
@ -60,8 +60,8 @@ export function useTooltipPosition({
|
|||||||
sidebarTooltip: boolean;
|
sidebarTooltip: boolean;
|
||||||
position: Position;
|
position: Position;
|
||||||
gap: number;
|
gap: number;
|
||||||
triggerRef: React.RefObject<HTMLElement | null>;
|
triggerRef: React.MutableRefObject<HTMLElement | null>;
|
||||||
tooltipRef: React.RefObject<HTMLDivElement | null>;
|
tooltipRef: React.MutableRefObject<HTMLDivElement | null>;
|
||||||
sidebarRefs?: SidebarRefs;
|
sidebarRefs?: SidebarRefs;
|
||||||
sidebarState?: SidebarState;
|
sidebarState?: SidebarState;
|
||||||
}): PositionState {
|
}): PositionState {
|
||||||
|
@ -5,8 +5,8 @@ export interface SidebarState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface SidebarRefs {
|
export interface SidebarRefs {
|
||||||
quickAccessRef: React.RefObject<HTMLDivElement | null>;
|
quickAccessRef: React.MutableRefObject<HTMLDivElement | null>;
|
||||||
toolPanelRef: React.RefObject<HTMLDivElement | null>;
|
toolPanelRef: React.MutableRefObject<HTMLDivElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SidebarInfo {
|
export interface SidebarInfo {
|
||||||
|
Loading…
Reference in New Issue
Block a user