mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
couple of small fixes for text editor (#5155)
# Description of Changes - Workbench.tsx: Allow PDF text editor to handle it's own custom state (this is a bit of a hotfix, we're going to handle the PDF text editors file upload flow better in a future PR). - PdfTextEditorView.tsx: Added a dropzone and some helper text to upload the first file. - PdfTextEditorView.tsx: Hide document view when isConverting is true. Prevents showing stale content from previous file during conversion. - useTranslatedToolRegistry.tsx: Moved PDF Text Editor to top of Recommended tools list. Increased visibility of the new feature. - PdfTextEditor.tsx: Removed auto-navigation to PDF Editor workbench on file selection. Stops the "jumpy" behavior when selecting files. - HomePage.tsx: Check specifically for pdfTextEditor tool instead of any custom workbench. Prevents auto-switch to viewer when uploading files while in PDF Text Editor. <img width="2056" height="1073" alt="Screenshot 2025-12-03 at 6 01 14 PM" src="https://github.com/user-attachments/assets/dfc63a46-7991-486c-ba00-0ce7637502f5" /> --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
co-authored by
Anthony Stirling
parent
f8dbf171e1
commit
c9bf436895
@@ -1,4 +1,4 @@
|
||||
import React, { createContext, useContext, useReducer, useCallback } from 'react';
|
||||
import React, { createContext, useContext, useReducer, useCallback, useMemo } from 'react';
|
||||
import { WorkbenchType, getDefaultWorkbench } from '@app/types/workbench';
|
||||
import { ToolId, isValidToolId } from '@app/types/toolId';
|
||||
import { useToolRegistry } from '@app/contexts/ToolRegistryContext';
|
||||
@@ -110,8 +110,8 @@ export const NavigationProvider: React.FC<{
|
||||
const { allTools: toolRegistry } = useToolRegistry();
|
||||
const unsavedChangesCheckerRef = React.useRef<(() => boolean) | null>(null);
|
||||
|
||||
const actions: NavigationContextActions = {
|
||||
setWorkbench: useCallback((workbench: WorkbenchType) => {
|
||||
// Memoize individual callbacks
|
||||
const setWorkbench = useCallback((workbench: WorkbenchType) => {
|
||||
// Check for unsaved changes using registered checker or state
|
||||
const hasUnsavedChanges = unsavedChangesCheckerRef.current?.() || state.hasUnsavedChanges;
|
||||
console.log('[NavigationContext] setWorkbench:', {
|
||||
@@ -152,13 +152,13 @@ export const NavigationProvider: React.FC<{
|
||||
} else {
|
||||
dispatch({ type: 'SET_WORKBENCH', payload: { workbench } });
|
||||
}
|
||||
}, [state.workbench, state.hasUnsavedChanges]),
|
||||
}, [state.workbench, state.hasUnsavedChanges]);
|
||||
|
||||
setSelectedTool: useCallback((toolId: ToolId | null) => {
|
||||
const setSelectedTool = useCallback((toolId: ToolId | null) => {
|
||||
dispatch({ type: 'SET_SELECTED_TOOL', payload: { toolId } });
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
setToolAndWorkbench: useCallback((toolId: ToolId | null, workbench: WorkbenchType) => {
|
||||
const setToolAndWorkbench = useCallback((toolId: ToolId | null, workbench: WorkbenchType) => {
|
||||
// Check for unsaved changes using registered checker or state
|
||||
const hasUnsavedChanges = unsavedChangesCheckerRef.current?.() || state.hasUnsavedChanges;
|
||||
|
||||
@@ -177,25 +177,25 @@ export const NavigationProvider: React.FC<{
|
||||
} else {
|
||||
dispatch({ type: 'SET_TOOL_AND_WORKBENCH', payload: { toolId, workbench } });
|
||||
}
|
||||
}, [state.workbench, state.hasUnsavedChanges]),
|
||||
}, [state.workbench, state.hasUnsavedChanges]);
|
||||
|
||||
setHasUnsavedChanges: useCallback((hasChanges: boolean) => {
|
||||
const setHasUnsavedChanges = useCallback((hasChanges: boolean) => {
|
||||
dispatch({ type: 'SET_UNSAVED_CHANGES', payload: { hasChanges } });
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
registerUnsavedChangesChecker: useCallback((checker: () => boolean) => {
|
||||
const registerUnsavedChangesChecker = useCallback((checker: () => boolean) => {
|
||||
unsavedChangesCheckerRef.current = checker;
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
unregisterUnsavedChangesChecker: useCallback(() => {
|
||||
const unregisterUnsavedChangesChecker = useCallback(() => {
|
||||
unsavedChangesCheckerRef.current = null;
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
showNavigationWarning: useCallback((show: boolean) => {
|
||||
const showNavigationWarning = useCallback((show: boolean) => {
|
||||
dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show } });
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
requestNavigation: useCallback((navigationFn: () => void) => {
|
||||
const requestNavigation = useCallback((navigationFn: () => void) => {
|
||||
if (!state.hasUnsavedChanges) {
|
||||
navigationFn();
|
||||
return;
|
||||
@@ -203,9 +203,9 @@ export const NavigationProvider: React.FC<{
|
||||
|
||||
dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn } });
|
||||
dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: true } });
|
||||
}, [state.hasUnsavedChanges]),
|
||||
}, [state.hasUnsavedChanges]);
|
||||
|
||||
confirmNavigation: useCallback(() => {
|
||||
const confirmNavigation = useCallback(() => {
|
||||
console.log('[NavigationContext] confirmNavigation called', {
|
||||
hasPendingNav: !!state.pendingNavigation,
|
||||
currentWorkbench: state.workbench,
|
||||
@@ -218,18 +218,18 @@ export const NavigationProvider: React.FC<{
|
||||
dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn: null } });
|
||||
dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: false } });
|
||||
console.log('[NavigationContext] confirmNavigation completed');
|
||||
}, [state.pendingNavigation, state.workbench, state.selectedTool]),
|
||||
}, [state.pendingNavigation, state.workbench, state.selectedTool]);
|
||||
|
||||
cancelNavigation: useCallback(() => {
|
||||
const cancelNavigation = useCallback(() => {
|
||||
dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn: null } });
|
||||
dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: false } });
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
clearToolSelection: useCallback(() => {
|
||||
const clearToolSelection = useCallback(() => {
|
||||
dispatch({ type: 'SET_TOOL_AND_WORKBENCH', payload: { toolId: null, workbench: getDefaultWorkbench() } });
|
||||
}, []),
|
||||
}, []);
|
||||
|
||||
handleToolSelect: useCallback((toolId: string) => {
|
||||
const handleToolSelect = useCallback((toolId: string) => {
|
||||
if (toolId === 'allTools') {
|
||||
dispatch({ type: 'SET_TOOL_AND_WORKBENCH', payload: { toolId: null, workbench: getDefaultWorkbench() } });
|
||||
return;
|
||||
@@ -245,11 +245,40 @@ export const NavigationProvider: React.FC<{
|
||||
const tool = isValidToolId(toolId)? toolRegistry[toolId] : null;
|
||||
const workbench = tool ? (tool.workbench || getDefaultWorkbench()) : getDefaultWorkbench();
|
||||
|
||||
// Validate toolId and convert to ToolId type
|
||||
const validToolId = isValidToolId(toolId) ? toolId : null;
|
||||
dispatch({ type: 'SET_TOOL_AND_WORKBENCH', payload: { toolId: validToolId, workbench } });
|
||||
}, [toolRegistry])
|
||||
};
|
||||
// Validate toolId and convert to ToolId type
|
||||
const validToolId = isValidToolId(toolId) ? toolId : null;
|
||||
dispatch({ type: 'SET_TOOL_AND_WORKBENCH', payload: { toolId: validToolId, workbench } });
|
||||
}, [toolRegistry]);
|
||||
|
||||
// Memoize the actions object to prevent unnecessary context updates
|
||||
// This is critical to avoid infinite loops when effects depend on actions
|
||||
const actions: NavigationContextActions = useMemo(() => ({
|
||||
setWorkbench,
|
||||
setSelectedTool,
|
||||
setToolAndWorkbench,
|
||||
setHasUnsavedChanges,
|
||||
registerUnsavedChangesChecker,
|
||||
unregisterUnsavedChangesChecker,
|
||||
showNavigationWarning,
|
||||
requestNavigation,
|
||||
confirmNavigation,
|
||||
cancelNavigation,
|
||||
clearToolSelection,
|
||||
handleToolSelect,
|
||||
}), [
|
||||
setWorkbench,
|
||||
setSelectedTool,
|
||||
setToolAndWorkbench,
|
||||
setHasUnsavedChanges,
|
||||
registerUnsavedChangesChecker,
|
||||
unregisterUnsavedChangesChecker,
|
||||
showNavigationWarning,
|
||||
requestNavigation,
|
||||
confirmNavigation,
|
||||
cancelNavigation,
|
||||
clearToolSelection,
|
||||
handleToolSelect,
|
||||
]);
|
||||
|
||||
const stateValue: NavigationContextStateValue = {
|
||||
workbench: state.workbench,
|
||||
@@ -259,9 +288,10 @@ export const NavigationProvider: React.FC<{
|
||||
showNavigationWarning: state.showNavigationWarning
|
||||
};
|
||||
|
||||
const actionsValue: NavigationContextActionsValue = {
|
||||
// Also memoize the context value to prevent unnecessary re-renders
|
||||
const actionsValue: NavigationContextActionsValue = useMemo(() => ({
|
||||
actions
|
||||
};
|
||||
}), [actions]);
|
||||
|
||||
return (
|
||||
<NavigationStateContext.Provider value={stateValue}>
|
||||
|
||||
@@ -224,11 +224,15 @@ export function ToolWorkflowProvider({ children }: ToolWorkflowProviderProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigationState.pendingNavigation || navigationState.showNavigationWarning) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentCustomView = customWorkbenchViews.find(view => view.workbenchId === navigationState.workbench);
|
||||
if (!currentCustomView || currentCustomView.data == null) {
|
||||
actions.setWorkbench(getDefaultWorkbench());
|
||||
}
|
||||
}, [actions, customWorkbenchViews, navigationState.workbench]);
|
||||
}, [actions, customWorkbenchViews, navigationState.workbench, navigationState.pendingNavigation, navigationState.showNavigationWarning]);
|
||||
|
||||
// Persisted via PreferencesContext; no direct localStorage writes needed here
|
||||
|
||||
|
||||
Reference in New Issue
Block a user