From 64b33ea62b4f656a0206d09e3c46aff10892eb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Sz=C3=BCcs?= <127139797+balazs-szucs@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:13:54 +0100 Subject: [PATCH] fix(annotations): fix error 300 on sign frontend (#5536) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description of Changes the bug https://github.com/user-attachments/assets/7f524c95-e57a-4188-a7a9-8d3020a3bb47 --- ## Checklist ### General - [X] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [X] 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) - [X] I have performed a self-review of my own code - [X] 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) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### 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) - [X] 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. Signed-off-by: Balázs Szücs --- frontend/src/core/components/shared/Tooltip.tsx | 5 ++++- .../shared/rightRail/ViewerAnnotationControls.tsx | 10 +++++----- frontend/src/core/contexts/FileContext.tsx | 6 ++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/frontend/src/core/components/shared/Tooltip.tsx b/frontend/src/core/components/shared/Tooltip.tsx index 10fefec02..2580b3530 100644 --- a/frontend/src/core/components/shared/Tooltip.tsx +++ b/frontend/src/core/components/shared/Tooltip.tsx @@ -83,7 +83,10 @@ export const Tooltip: React.FC = ({ } }, []); - const sidebarContext = sidebarTooltip ? useSidebarContext() : null; + // Always call the hook unconditionally to satisfy React's rules of hooks. + // The context is only used when sidebarTooltip is true. + const sidebarContextValue = useSidebarContext(); + const sidebarContext = sidebarTooltip ? sidebarContextValue : null; const isControlled = controlledOpen !== undefined; const open = (isControlled ? !!controlledOpen : internalOpen) && !disabled; diff --git a/frontend/src/core/components/shared/rightRail/ViewerAnnotationControls.tsx b/frontend/src/core/components/shared/rightRail/ViewerAnnotationControls.tsx index 54eec53f9..f4bbb386f 100644 --- a/frontend/src/core/components/shared/rightRail/ViewerAnnotationControls.tsx +++ b/frontend/src/core/components/shared/rightRail/ViewerAnnotationControls.tsx @@ -55,11 +55,6 @@ export default function ViewerAnnotationControls({ currentView, disabled = false const isAnnotateActive = selectedTool === 'annotate'; const annotationsHidden = viewerContext ? !viewerContext.isAnnotationsVisible : false; - // Don't show any annotation controls in sign mode - if (isSignMode) { - return null; - } - // Persist annotations to file if there are unsaved changes const saveAnnotationsIfNeeded = async () => { if (!viewerContext?.exportActions?.saveAsCopy || currentView !== 'viewer' || !historyApiRef?.current?.canUndo()) return; @@ -135,6 +130,11 @@ export default function ViewerAnnotationControls({ currentView, disabled = false } }; + // Don't show any annotation controls in sign mode + // NOTE: This early return is placed AFTER all hooks to satisfy React's rules of hooks + if (isSignMode) { + return null; + } return ( <> diff --git a/frontend/src/core/contexts/FileContext.tsx b/frontend/src/core/contexts/FileContext.tsx index 378d43050..f63ae0f69 100644 --- a/frontend/src/core/contexts/FileContext.tsx +++ b/frontend/src/core/contexts/FileContext.tsx @@ -54,8 +54,10 @@ function FileContextInner({ }: FileContextProviderProps) { const [state, dispatch] = useReducer(fileContextReducer, initialFileContextState); - // IndexedDB context for persistence - const indexedDB = enablePersistence ? useIndexedDB() : null; + // Always call the hook unconditionally to satisfy React's rules of hooks. + // IndexedDB context is only used when enablePersistence is true. + const indexedDBValue = useIndexedDB(); + const indexedDB = enablePersistence ? indexedDBValue : null; // File ref map - stores File objects outside React state const filesRef = useRef>(new Map());