mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 01:19:24 +00:00
Clean up
This commit is contained in:
parent
72375d89d1
commit
312fc2d615
@ -7,7 +7,6 @@ import { useRightRail } from '../../contexts/RightRailContext';
|
|||||||
import { useFileState, useFileSelection, useFileManagement } from '../../contexts/FileContext';
|
import { useFileState, useFileSelection, useFileManagement } from '../../contexts/FileContext';
|
||||||
import { useNavigationState } from '../../contexts/NavigationContext';
|
import { useNavigationState } from '../../contexts/NavigationContext';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import '../../types/embedPdf';
|
|
||||||
|
|
||||||
import LanguageSelector from '../shared/LanguageSelector';
|
import LanguageSelector from '../shared/LanguageSelector';
|
||||||
import { useRainbowThemeContext } from '../shared/RainbowThemeProvider';
|
import { useRainbowThemeContext } from '../shared/RainbowThemeProvider';
|
||||||
|
@ -9,7 +9,6 @@ import { useViewer } from "../../contexts/ViewerContext";
|
|||||||
import { LocalEmbedPDF } from './LocalEmbedPDF';
|
import { LocalEmbedPDF } from './LocalEmbedPDF';
|
||||||
import { PdfViewerToolbar } from './PdfViewerToolbar';
|
import { PdfViewerToolbar } from './PdfViewerToolbar';
|
||||||
import { ThumbnailSidebar } from './ThumbnailSidebar';
|
import { ThumbnailSidebar } from './ThumbnailSidebar';
|
||||||
import '../../types/embedPdf';
|
|
||||||
|
|
||||||
export interface EmbedPdfViewerProps {
|
export interface EmbedPdfViewerProps {
|
||||||
sidebarsVisible: boolean;
|
sidebarsVisible: boolean;
|
||||||
@ -200,7 +199,7 @@ const EmbedPdfViewerContent = ({
|
|||||||
currentPage={scrollState.currentPage}
|
currentPage={scrollState.currentPage}
|
||||||
totalPages={scrollState.totalPages}
|
totalPages={scrollState.totalPages}
|
||||||
onPageChange={(page) => {
|
onPageChange={(page) => {
|
||||||
// Placeholder - will implement page navigation later
|
// Page navigation handled by scrollActions
|
||||||
console.log('Navigate to page:', page);
|
console.log('Navigate to page:', page);
|
||||||
}}
|
}}
|
||||||
dualPage={spreadState.isDualPage}
|
dualPage={spreadState.isDualPage}
|
||||||
|
@ -8,7 +8,6 @@ import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
|
|||||||
import LastPageIcon from '@mui/icons-material/LastPage';
|
import LastPageIcon from '@mui/icons-material/LastPage';
|
||||||
import DescriptionIcon from '@mui/icons-material/Description';
|
import DescriptionIcon from '@mui/icons-material/Description';
|
||||||
import ViewWeekIcon from '@mui/icons-material/ViewWeek';
|
import ViewWeekIcon from '@mui/icons-material/ViewWeek';
|
||||||
import '../../types/embedPdf';
|
|
||||||
|
|
||||||
interface PdfViewerToolbarProps {
|
interface PdfViewerToolbarProps {
|
||||||
// Page navigation props (placeholders for now)
|
// Page navigation props (placeholders for now)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useScroll } from '@embedpdf/plugin-scroll/react';
|
import { useScroll } from '@embedpdf/plugin-scroll/react';
|
||||||
import { useViewer } from '../../contexts/ViewerContext';
|
import { useViewer } from '../../contexts/ViewerContext';
|
||||||
|
|
||||||
@ -10,11 +10,6 @@ export function ScrollAPIBridge() {
|
|||||||
const { provides: scroll, state: scrollState } = useScroll();
|
const { provides: scroll, state: scrollState } = useScroll();
|
||||||
const { registerBridge, triggerImmediateScrollUpdate } = useViewer();
|
const { registerBridge, triggerImmediateScrollUpdate } = useViewer();
|
||||||
|
|
||||||
const [_localState, setLocalState] = useState({
|
|
||||||
currentPage: 1,
|
|
||||||
totalPages: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scroll && scrollState) {
|
if (scroll && scrollState) {
|
||||||
const newState = {
|
const newState = {
|
||||||
@ -22,15 +17,8 @@ export function ScrollAPIBridge() {
|
|||||||
totalPages: scrollState.totalPages,
|
totalPages: scrollState.totalPages,
|
||||||
};
|
};
|
||||||
|
|
||||||
setLocalState(prevState => {
|
// Trigger immediate update for responsive UI
|
||||||
// Only update if state actually changed
|
triggerImmediateScrollUpdate(newState.currentPage, newState.totalPages);
|
||||||
if (prevState.currentPage !== newState.currentPage || prevState.totalPages !== newState.totalPages) {
|
|
||||||
// Trigger immediate update for responsive UI
|
|
||||||
triggerImmediateScrollUpdate(newState.currentPage, newState.totalPages);
|
|
||||||
return newState;
|
|
||||||
}
|
|
||||||
return prevState;
|
|
||||||
});
|
|
||||||
|
|
||||||
registerBridge('scroll', {
|
registerBridge('scroll', {
|
||||||
state: newState,
|
state: newState,
|
||||||
|
@ -13,8 +13,9 @@ export function SearchInterface({ visible, onClose }: SearchInterfaceProps) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const viewerContext = React.useContext(ViewerContext);
|
const viewerContext = React.useContext(ViewerContext);
|
||||||
|
|
||||||
const searchResults = viewerContext?.getSearchResults();
|
const searchState = viewerContext?.getSearchState();
|
||||||
const searchActiveIndex = viewerContext?.getSearchActiveIndex();
|
const searchResults = searchState?.results;
|
||||||
|
const searchActiveIndex = searchState?.activeIndex;
|
||||||
const searchActions = viewerContext?.searchActions;
|
const searchActions = viewerContext?.searchActions;
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [jumpToValue, setJumpToValue] = useState('');
|
const [jumpToValue, setJumpToValue] = useState('');
|
||||||
|
@ -10,18 +10,11 @@ export function SelectionAPIBridge() {
|
|||||||
const { registerBridge } = useViewer();
|
const { registerBridge } = useViewer();
|
||||||
const [hasSelection, setHasSelection] = useState(false);
|
const [hasSelection, setHasSelection] = useState(false);
|
||||||
|
|
||||||
// Store state locally
|
|
||||||
const [_localState, setLocalState] = useState({
|
|
||||||
hasSelection: false
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selection) {
|
if (selection) {
|
||||||
// Update local state
|
|
||||||
const newState = {
|
const newState = {
|
||||||
hasSelection
|
hasSelection
|
||||||
};
|
};
|
||||||
setLocalState(newState);
|
|
||||||
|
|
||||||
// Register this bridge with ViewerContext
|
// Register this bridge with ViewerContext
|
||||||
registerBridge('selection', {
|
registerBridge('selection', {
|
||||||
@ -38,7 +31,6 @@ export function SelectionAPIBridge() {
|
|||||||
const hasText = !!sel;
|
const hasText = !!sel;
|
||||||
setHasSelection(hasText);
|
setHasSelection(hasText);
|
||||||
const updatedState = { hasSelection: hasText };
|
const updatedState = { hasSelection: hasText };
|
||||||
setLocalState(updatedState);
|
|
||||||
// Re-register with updated state
|
// Re-register with updated state
|
||||||
registerBridge('selection', {
|
registerBridge('selection', {
|
||||||
state: updatedState,
|
state: updatedState,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useSpread, SpreadMode } from '@embedpdf/plugin-spread/react';
|
import { useSpread, SpreadMode } from '@embedpdf/plugin-spread/react';
|
||||||
import { useViewer } from '../../contexts/ViewerContext';
|
import { useViewer } from '../../contexts/ViewerContext';
|
||||||
|
|
||||||
@ -9,20 +9,12 @@ export function SpreadAPIBridge() {
|
|||||||
const { provides: spread, spreadMode } = useSpread();
|
const { provides: spread, spreadMode } = useSpread();
|
||||||
const { registerBridge } = useViewer();
|
const { registerBridge } = useViewer();
|
||||||
|
|
||||||
// Store state locally
|
|
||||||
const [_localState, setLocalState] = useState({
|
|
||||||
spreadMode: SpreadMode.None,
|
|
||||||
isDualPage: false
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (spread) {
|
if (spread) {
|
||||||
// Update local state
|
|
||||||
const newState = {
|
const newState = {
|
||||||
spreadMode,
|
spreadMode,
|
||||||
isDualPage: spreadMode !== SpreadMode.None
|
isDualPage: spreadMode !== SpreadMode.None
|
||||||
};
|
};
|
||||||
setLocalState(newState);
|
|
||||||
|
|
||||||
// Register this bridge with ViewerContext
|
// Register this bridge with ViewerContext
|
||||||
registerBridge('spread', {
|
registerBridge('spread', {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Box, ScrollArea } from '@mantine/core';
|
import { Box, ScrollArea } from '@mantine/core';
|
||||||
import { useViewer } from '../../contexts/ViewerContext';
|
import { useViewer } from '../../contexts/ViewerContext';
|
||||||
import '../../types/embedPdf';
|
|
||||||
|
|
||||||
interface ThumbnailSidebarProps {
|
interface ThumbnailSidebarProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -19,39 +18,25 @@ export function ThumbnailSidebar({ visible, onToggle: _onToggle }: ThumbnailSide
|
|||||||
// Generate thumbnails when sidebar becomes visible
|
// Generate thumbnails when sidebar becomes visible
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!visible || scrollState.totalPages === 0) return;
|
if (!visible || scrollState.totalPages === 0) return;
|
||||||
|
|
||||||
console.log('📄 ThumbnailSidebar useEffect triggered:', {
|
|
||||||
visible,
|
|
||||||
thumbnailAPI: !!thumbnailAPI,
|
|
||||||
totalPages: scrollState.totalPages,
|
|
||||||
existingThumbnails: Object.keys(thumbnails).length
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!thumbnailAPI) return;
|
if (!thumbnailAPI) return;
|
||||||
|
|
||||||
const generateThumbnails = async () => {
|
const generateThumbnails = async () => {
|
||||||
console.log('📄 Starting thumbnail generation for', scrollState.totalPages, 'pages');
|
|
||||||
|
|
||||||
for (let pageIndex = 0; pageIndex < scrollState.totalPages; pageIndex++) {
|
for (let pageIndex = 0; pageIndex < scrollState.totalPages; pageIndex++) {
|
||||||
if (thumbnails[pageIndex]) continue; // Skip if already generated
|
if (thumbnails[pageIndex]) continue; // Skip if already generated
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('📄 Attempting to generate thumbnail for page', pageIndex + 1);
|
const thumbTask = (thumbnailAPI as any).renderThumb(pageIndex, 1.0);
|
||||||
const thumbTask = thumbnailAPI.renderThumb(pageIndex, 1.0);
|
|
||||||
console.log('📄 Received thumbTask:', thumbTask);
|
|
||||||
|
|
||||||
// Convert Task to Promise and handle properly
|
// Convert Task to Promise and handle properly
|
||||||
thumbTask.toPromise().then((thumbBlob: Blob) => {
|
thumbTask.toPromise().then((thumbBlob: Blob) => {
|
||||||
console.log('📄 Thumbnail generated successfully for page', pageIndex + 1, 'blob:', thumbBlob);
|
|
||||||
const thumbUrl = URL.createObjectURL(thumbBlob);
|
const thumbUrl = URL.createObjectURL(thumbBlob);
|
||||||
console.log('📄 Created blob URL:', thumbUrl);
|
|
||||||
|
|
||||||
setThumbnails(prev => ({
|
setThumbnails(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[pageIndex]: thumbUrl
|
[pageIndex]: thumbUrl
|
||||||
}));
|
}));
|
||||||
}).catch((error: any) => {
|
}).catch((error: any) => {
|
||||||
console.error('📄 Failed to generate thumbnail for page', pageIndex + 1, error);
|
console.error('Failed to generate thumbnail for page', pageIndex + 1, error);
|
||||||
setThumbnails(prev => ({
|
setThumbnails(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[pageIndex]: 'error'
|
[pageIndex]: 'error'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { useZoom } from '@embedpdf/plugin-zoom/react';
|
import { useZoom } from '@embedpdf/plugin-zoom/react';
|
||||||
import { useViewer } from '../../contexts/ViewerContext';
|
import { useViewer } from '../../contexts/ViewerContext';
|
||||||
|
|
||||||
@ -7,21 +7,14 @@ import { useViewer } from '../../contexts/ViewerContext';
|
|||||||
*/
|
*/
|
||||||
export function ZoomAPIBridge() {
|
export function ZoomAPIBridge() {
|
||||||
const { provides: zoom, state: zoomState } = useZoom();
|
const { provides: zoom, state: zoomState } = useZoom();
|
||||||
const { registerBridge } = useViewer();
|
const { registerBridge, triggerImmediateZoomUpdate } = useViewer();
|
||||||
const hasSetInitialZoom = useRef(false);
|
const hasSetInitialZoom = useRef(false);
|
||||||
|
|
||||||
// Store state locally
|
|
||||||
const [_localState, setLocalState] = useState({
|
|
||||||
currentZoom: 1.4,
|
|
||||||
zoomPercent: 140
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set initial zoom once when plugin is ready
|
// Set initial zoom once when plugin is ready
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (zoom && !hasSetInitialZoom.current) {
|
if (zoom && !hasSetInitialZoom.current) {
|
||||||
hasSetInitialZoom.current = true;
|
hasSetInitialZoom.current = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
console.log('Setting initial zoom to 140%');
|
|
||||||
zoom.requestZoom(1.4);
|
zoom.requestZoom(1.4);
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
@ -36,9 +29,8 @@ export function ZoomAPIBridge() {
|
|||||||
zoomPercent: Math.round(currentZoomLevel * 100),
|
zoomPercent: Math.round(currentZoomLevel * 100),
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('ZoomAPIBridge - Raw zoom level:', currentZoomLevel, 'Rounded percent:', newState.zoomPercent);
|
// Trigger immediate update for responsive UI
|
||||||
|
triggerImmediateZoomUpdate(newState.zoomPercent);
|
||||||
setLocalState(newState);
|
|
||||||
|
|
||||||
// Register this bridge with ViewerContext
|
// Register this bridge with ViewerContext
|
||||||
registerBridge('zoom', {
|
registerBridge('zoom', {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { createContext, useContext, useState, ReactNode, useRef } from 'react';
|
import React, { createContext, useContext, useState, ReactNode, useRef } from 'react';
|
||||||
|
import { SpreadMode } from '@embedpdf/plugin-spread/react';
|
||||||
|
|
||||||
// State interfaces - represent the shape of data from each bridge
|
// State interfaces - represent the shape of data from each bridge
|
||||||
interface ScrollState {
|
interface ScrollState {
|
||||||
@ -20,7 +21,7 @@ interface SelectionState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface SpreadState {
|
interface SpreadState {
|
||||||
spreadMode: any;
|
spreadMode: SpreadMode;
|
||||||
isDualPage: boolean;
|
isDualPage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,10 +29,15 @@ interface RotationState {
|
|||||||
rotation: number;
|
rotation: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SearchState {
|
||||||
|
results: any[] | null;
|
||||||
|
activeIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
// Bridge registration interface - bridges register with state and API
|
// Bridge registration interface - bridges register with state and API
|
||||||
interface BridgeRef {
|
interface BridgeRef<TState = unknown, TApi = unknown> {
|
||||||
state: any;
|
state: TState;
|
||||||
api: any;
|
api: TApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,9 +61,8 @@ interface ViewerContextType {
|
|||||||
getSelectionState: () => SelectionState;
|
getSelectionState: () => SelectionState;
|
||||||
getSpreadState: () => SpreadState;
|
getSpreadState: () => SpreadState;
|
||||||
getRotationState: () => RotationState;
|
getRotationState: () => RotationState;
|
||||||
getSearchResults: () => any[] | null;
|
getSearchState: () => SearchState;
|
||||||
getSearchActiveIndex: () => number;
|
getThumbnailAPI: () => unknown;
|
||||||
getThumbnailAPI: () => any;
|
|
||||||
|
|
||||||
// Immediate update callbacks
|
// Immediate update callbacks
|
||||||
registerImmediateZoomUpdate: (callback: (percent: number) => void) => void;
|
registerImmediateZoomUpdate: (callback: (percent: number) => void) => void;
|
||||||
@ -65,6 +70,7 @@ interface ViewerContextType {
|
|||||||
|
|
||||||
// Internal - for bridges to trigger immediate updates
|
// Internal - for bridges to trigger immediate updates
|
||||||
triggerImmediateScrollUpdate: (currentPage: number, totalPages: number) => void;
|
triggerImmediateScrollUpdate: (currentPage: number, totalPages: number) => void;
|
||||||
|
triggerImmediateZoomUpdate: (zoomPercent: number) => void;
|
||||||
|
|
||||||
// Action handlers - call EmbedPDF APIs directly
|
// Action handlers - call EmbedPDF APIs directly
|
||||||
scrollActions: {
|
scrollActions: {
|
||||||
@ -91,12 +97,12 @@ interface ViewerContextType {
|
|||||||
selectionActions: {
|
selectionActions: {
|
||||||
copyToClipboard: () => void;
|
copyToClipboard: () => void;
|
||||||
getSelectedText: () => string;
|
getSelectedText: () => string;
|
||||||
getFormattedSelection: () => any;
|
getFormattedSelection: () => unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
spreadActions: {
|
spreadActions: {
|
||||||
setSpreadMode: (mode: any) => void;
|
setSpreadMode: (mode: SpreadMode) => void;
|
||||||
getSpreadMode: () => any;
|
getSpreadMode: () => SpreadMode;
|
||||||
toggleSpreadMode: () => void;
|
toggleSpreadMode: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,14 +136,14 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
// Bridge registry - bridges register their state and APIs here
|
// Bridge registry - bridges register their state and APIs here
|
||||||
const bridgeRefs = useRef({
|
const bridgeRefs = useRef({
|
||||||
scroll: null as BridgeRef | null,
|
scroll: null as BridgeRef<ScrollState> | null,
|
||||||
zoom: null as BridgeRef | null,
|
zoom: null as BridgeRef<ZoomState> | null,
|
||||||
pan: null as BridgeRef | null,
|
pan: null as BridgeRef<PanState> | null,
|
||||||
selection: null as BridgeRef | null,
|
selection: null as BridgeRef<SelectionState> | null,
|
||||||
search: null as BridgeRef | null,
|
search: null as BridgeRef<SearchState> | null,
|
||||||
spread: null as BridgeRef | null,
|
spread: null as BridgeRef<SpreadState> | null,
|
||||||
rotation: null as BridgeRef | null,
|
rotation: null as BridgeRef<RotationState> | null,
|
||||||
thumbnail: null as BridgeRef | null,
|
thumbnail: null as BridgeRef<unknown> | null,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Immediate zoom callback for responsive display updates
|
// Immediate zoom callback for responsive display updates
|
||||||
@ -147,7 +153,7 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
const immediateScrollUpdateCallback = useRef<((currentPage: number, totalPages: number) => void) | null>(null);
|
const immediateScrollUpdateCallback = useRef<((currentPage: number, totalPages: number) => void) | null>(null);
|
||||||
|
|
||||||
const registerBridge = (type: string, ref: BridgeRef) => {
|
const registerBridge = (type: string, ref: BridgeRef) => {
|
||||||
bridgeRefs.current[type as keyof typeof bridgeRefs.current] = ref;
|
(bridgeRefs.current as any)[type] = ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleThumbnailSidebar = () => {
|
const toggleThumbnailSidebar = () => {
|
||||||
@ -172,19 +178,15 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getSpreadState = (): SpreadState => {
|
const getSpreadState = (): SpreadState => {
|
||||||
return bridgeRefs.current.spread?.state || { spreadMode: null, isDualPage: false };
|
return bridgeRefs.current.spread?.state || { spreadMode: SpreadMode.None, isDualPage: false };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRotationState = (): RotationState => {
|
const getRotationState = (): RotationState => {
|
||||||
return bridgeRefs.current.rotation?.state || { rotation: 0 };
|
return bridgeRefs.current.rotation?.state || { rotation: 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSearchResults = () => {
|
const getSearchState = (): SearchState => {
|
||||||
return bridgeRefs.current.search?.state?.results || null;
|
return bridgeRefs.current.search?.state || { results: null, activeIndex: 0 };
|
||||||
};
|
|
||||||
|
|
||||||
const getSearchActiveIndex = () => {
|
|
||||||
return bridgeRefs.current.search?.state?.activeIndex || 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getThumbnailAPI = () => {
|
const getThumbnailAPI = () => {
|
||||||
@ -194,32 +196,32 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
// Action handlers - call APIs directly
|
// Action handlers - call APIs directly
|
||||||
const scrollActions = {
|
const scrollActions = {
|
||||||
scrollToPage: (page: number) => {
|
scrollToPage: (page: number) => {
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
const api = bridgeRefs.current.scroll?.api as any;
|
||||||
if (api?.scrollToPage) {
|
if (api?.scrollToPage) {
|
||||||
api.scrollToPage({ pageNumber: page });
|
api.scrollToPage({ pageNumber: page });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollToFirstPage: () => {
|
scrollToFirstPage: () => {
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
const api = bridgeRefs.current.scroll?.api as any;
|
||||||
if (api?.scrollToPage) {
|
if (api?.scrollToPage) {
|
||||||
api.scrollToPage({ pageNumber: 1 });
|
api.scrollToPage({ pageNumber: 1 });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollToPreviousPage: () => {
|
scrollToPreviousPage: () => {
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
const api = bridgeRefs.current.scroll?.api as any;
|
||||||
if (api?.scrollToPreviousPage) {
|
if (api?.scrollToPreviousPage) {
|
||||||
api.scrollToPreviousPage();
|
api.scrollToPreviousPage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollToNextPage: () => {
|
scrollToNextPage: () => {
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
const api = bridgeRefs.current.scroll?.api as any;
|
||||||
if (api?.scrollToNextPage) {
|
if (api?.scrollToNextPage) {
|
||||||
api.scrollToNextPage();
|
api.scrollToNextPage();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollToLastPage: () => {
|
scrollToLastPage: () => {
|
||||||
const scrollState = getScrollState();
|
const scrollState = getScrollState();
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
const api = bridgeRefs.current.scroll?.api as any;
|
||||||
if (api?.scrollToPage && scrollState.totalPages > 0) {
|
if (api?.scrollToPage && scrollState.totalPages > 0) {
|
||||||
api.scrollToPage({ pageNumber: scrollState.totalPages });
|
api.scrollToPage({ pageNumber: scrollState.totalPages });
|
||||||
}
|
}
|
||||||
@ -228,7 +230,7 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
const zoomActions = {
|
const zoomActions = {
|
||||||
zoomIn: () => {
|
zoomIn: () => {
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
const api = bridgeRefs.current.zoom?.api as any;
|
||||||
if (api?.zoomIn) {
|
if (api?.zoomIn) {
|
||||||
// Update display immediately if callback is registered
|
// Update display immediately if callback is registered
|
||||||
if (immediateZoomUpdateCallback.current) {
|
if (immediateZoomUpdateCallback.current) {
|
||||||
@ -240,7 +242,7 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
zoomOut: () => {
|
zoomOut: () => {
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
const api = bridgeRefs.current.zoom?.api as any;
|
||||||
if (api?.zoomOut) {
|
if (api?.zoomOut) {
|
||||||
// Update display immediately if callback is registered
|
// Update display immediately if callback is registered
|
||||||
if (immediateZoomUpdateCallback.current) {
|
if (immediateZoomUpdateCallback.current) {
|
||||||
@ -252,13 +254,13 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleMarqueeZoom: () => {
|
toggleMarqueeZoom: () => {
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
const api = bridgeRefs.current.zoom?.api as any;
|
||||||
if (api?.toggleMarqueeZoom) {
|
if (api?.toggleMarqueeZoom) {
|
||||||
api.toggleMarqueeZoom();
|
api.toggleMarqueeZoom();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
requestZoom: (level: number) => {
|
requestZoom: (level: number) => {
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
const api = bridgeRefs.current.zoom?.api as any;
|
||||||
if (api?.requestZoom) {
|
if (api?.requestZoom) {
|
||||||
api.requestZoom(level);
|
api.requestZoom(level);
|
||||||
}
|
}
|
||||||
@ -267,19 +269,19 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
const panActions = {
|
const panActions = {
|
||||||
enablePan: () => {
|
enablePan: () => {
|
||||||
const api = bridgeRefs.current.pan?.api;
|
const api = bridgeRefs.current.pan?.api as any;
|
||||||
if (api?.enable) {
|
if (api?.enable) {
|
||||||
api.enable();
|
api.enable();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
disablePan: () => {
|
disablePan: () => {
|
||||||
const api = bridgeRefs.current.pan?.api;
|
const api = bridgeRefs.current.pan?.api as any;
|
||||||
if (api?.disable) {
|
if (api?.disable) {
|
||||||
api.disable();
|
api.disable();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
togglePan: () => {
|
togglePan: () => {
|
||||||
const api = bridgeRefs.current.pan?.api;
|
const api = bridgeRefs.current.pan?.api as any;
|
||||||
if (api?.toggle) {
|
if (api?.toggle) {
|
||||||
api.toggle();
|
api.toggle();
|
||||||
}
|
}
|
||||||
@ -288,20 +290,20 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
const selectionActions = {
|
const selectionActions = {
|
||||||
copyToClipboard: () => {
|
copyToClipboard: () => {
|
||||||
const api = bridgeRefs.current.selection?.api;
|
const api = bridgeRefs.current.selection?.api as any;
|
||||||
if (api?.copyToClipboard) {
|
if (api?.copyToClipboard) {
|
||||||
api.copyToClipboard();
|
api.copyToClipboard();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSelectedText: () => {
|
getSelectedText: () => {
|
||||||
const api = bridgeRefs.current.selection?.api;
|
const api = bridgeRefs.current.selection?.api as any;
|
||||||
if (api?.getSelectedText) {
|
if (api?.getSelectedText) {
|
||||||
return api.getSelectedText();
|
return api.getSelectedText();
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
getFormattedSelection: () => {
|
getFormattedSelection: () => {
|
||||||
const api = bridgeRefs.current.selection?.api;
|
const api = bridgeRefs.current.selection?.api as any;
|
||||||
if (api?.getFormattedSelection) {
|
if (api?.getFormattedSelection) {
|
||||||
return api.getFormattedSelection();
|
return api.getFormattedSelection();
|
||||||
}
|
}
|
||||||
@ -310,21 +312,21 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const spreadActions = {
|
const spreadActions = {
|
||||||
setSpreadMode: (mode: any) => {
|
setSpreadMode: (mode: SpreadMode) => {
|
||||||
const api = bridgeRefs.current.spread?.api;
|
const api = bridgeRefs.current.spread?.api as any;
|
||||||
if (api?.setSpreadMode) {
|
if (api?.setSpreadMode) {
|
||||||
api.setSpreadMode(mode);
|
api.setSpreadMode(mode);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSpreadMode: () => {
|
getSpreadMode: () => {
|
||||||
const api = bridgeRefs.current.spread?.api;
|
const api = bridgeRefs.current.spread?.api as any;
|
||||||
if (api?.getSpreadMode) {
|
if (api?.getSpreadMode) {
|
||||||
return api.getSpreadMode();
|
return api.getSpreadMode();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
toggleSpreadMode: () => {
|
toggleSpreadMode: () => {
|
||||||
const api = bridgeRefs.current.spread?.api;
|
const api = bridgeRefs.current.spread?.api as any;
|
||||||
if (api?.toggleSpreadMode) {
|
if (api?.toggleSpreadMode) {
|
||||||
api.toggleSpreadMode();
|
api.toggleSpreadMode();
|
||||||
}
|
}
|
||||||
@ -333,25 +335,25 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
const rotationActions = {
|
const rotationActions = {
|
||||||
rotateForward: () => {
|
rotateForward: () => {
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
const api = bridgeRefs.current.rotation?.api as any;
|
||||||
if (api?.rotateForward) {
|
if (api?.rotateForward) {
|
||||||
api.rotateForward();
|
api.rotateForward();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rotateBackward: () => {
|
rotateBackward: () => {
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
const api = bridgeRefs.current.rotation?.api as any;
|
||||||
if (api?.rotateBackward) {
|
if (api?.rotateBackward) {
|
||||||
api.rotateBackward();
|
api.rotateBackward();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setRotation: (rotation: number) => {
|
setRotation: (rotation: number) => {
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
const api = bridgeRefs.current.rotation?.api as any;
|
||||||
if (api?.setRotation) {
|
if (api?.setRotation) {
|
||||||
api.setRotation(rotation);
|
api.setRotation(rotation);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getRotation: () => {
|
getRotation: () => {
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
const api = bridgeRefs.current.rotation?.api as any;
|
||||||
if (api?.getRotation) {
|
if (api?.getRotation) {
|
||||||
return api.getRotation();
|
return api.getRotation();
|
||||||
}
|
}
|
||||||
@ -361,25 +363,25 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
|
|
||||||
const searchActions = {
|
const searchActions = {
|
||||||
search: async (query: string) => {
|
search: async (query: string) => {
|
||||||
const api = bridgeRefs.current.search?.api;
|
const api = bridgeRefs.current.search?.api as any;
|
||||||
if (api?.search) {
|
if (api?.search) {
|
||||||
return api.search(query);
|
return api.search(query);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
next: () => {
|
next: () => {
|
||||||
const api = bridgeRefs.current.search?.api;
|
const api = bridgeRefs.current.search?.api as any;
|
||||||
if (api?.next) {
|
if (api?.next) {
|
||||||
api.next();
|
api.next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
previous: () => {
|
previous: () => {
|
||||||
const api = bridgeRefs.current.search?.api;
|
const api = bridgeRefs.current.search?.api as any;
|
||||||
if (api?.previous) {
|
if (api?.previous) {
|
||||||
api.previous();
|
api.previous();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clear: () => {
|
clear: () => {
|
||||||
const api = bridgeRefs.current.search?.api;
|
const api = bridgeRefs.current.search?.api as any;
|
||||||
if (api?.clear) {
|
if (api?.clear) {
|
||||||
api.clear();
|
api.clear();
|
||||||
}
|
}
|
||||||
@ -400,6 +402,12 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const triggerImmediateZoomUpdate = (zoomPercent: number) => {
|
||||||
|
if (immediateZoomUpdateCallback.current) {
|
||||||
|
immediateZoomUpdateCallback.current(zoomPercent);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const value: ViewerContextType = {
|
const value: ViewerContextType = {
|
||||||
// UI state
|
// UI state
|
||||||
isThumbnailSidebarVisible,
|
isThumbnailSidebarVisible,
|
||||||
@ -412,14 +420,14 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
getSelectionState,
|
getSelectionState,
|
||||||
getSpreadState,
|
getSpreadState,
|
||||||
getRotationState,
|
getRotationState,
|
||||||
getSearchResults,
|
getSearchState,
|
||||||
getSearchActiveIndex,
|
|
||||||
getThumbnailAPI,
|
getThumbnailAPI,
|
||||||
|
|
||||||
// Immediate updates
|
// Immediate updates
|
||||||
registerImmediateZoomUpdate,
|
registerImmediateZoomUpdate,
|
||||||
registerImmediateScrollUpdate,
|
registerImmediateScrollUpdate,
|
||||||
triggerImmediateScrollUpdate,
|
triggerImmediateScrollUpdate,
|
||||||
|
triggerImmediateZoomUpdate,
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
scrollActions,
|
scrollActions,
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
// Types for EmbedPDF global APIs
|
|
||||||
export interface EmbedPdfZoomAPI {
|
|
||||||
zoomPercent: number;
|
|
||||||
zoomIn: () => void;
|
|
||||||
zoomOut: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfScrollAPI {
|
|
||||||
currentPage: number;
|
|
||||||
totalPages: number;
|
|
||||||
scrollToPage: (page: number) => void;
|
|
||||||
scrollToFirstPage: () => void;
|
|
||||||
scrollToPreviousPage: () => void;
|
|
||||||
scrollToNextPage: () => void;
|
|
||||||
scrollToLastPage: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfPanAPI {
|
|
||||||
isPanning: boolean;
|
|
||||||
togglePan: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfSpreadAPI {
|
|
||||||
toggleSpreadMode: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfRotateAPI {
|
|
||||||
rotateForward: () => void;
|
|
||||||
rotateBackward: () => void;
|
|
||||||
setRotation: (rotation: number) => void;
|
|
||||||
getRotation: () => number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfControlsAPI {
|
|
||||||
pointer: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedPdfThumbnailAPI {
|
|
||||||
thumbnailAPI: {
|
|
||||||
renderThumb: (pageIndex: number, scale: number) => {
|
|
||||||
toPromise: () => Promise<Blob>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
embedPdfZoom?: EmbedPdfZoomAPI;
|
|
||||||
embedPdfScroll?: EmbedPdfScrollAPI;
|
|
||||||
embedPdfPan?: EmbedPdfPanAPI;
|
|
||||||
embedPdfSpread?: EmbedPdfSpreadAPI;
|
|
||||||
embedPdfRotate?: EmbedPdfRotateAPI;
|
|
||||||
embedPdfControls?: EmbedPdfControlsAPI;
|
|
||||||
embedPdfThumbnail?: EmbedPdfThumbnailAPI;
|
|
||||||
toggleThumbnailSidebar?: () => void;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user