mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
Dedicated viewer actions
This commit is contained in:
parent
fad16f6ed0
commit
f6063c1e74
@ -7,6 +7,7 @@ import React, {
|
|||||||
useCallback,
|
useCallback,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useNavigation } from '@app/contexts/NavigationContext';
|
import { useNavigation } from '@app/contexts/NavigationContext';
|
||||||
|
import { createViewerActions } from '@core/contexts/viewer/viewerActions';
|
||||||
import {
|
import {
|
||||||
BridgeRef,
|
BridgeRef,
|
||||||
BridgeApiMap,
|
BridgeApiMap,
|
||||||
@ -99,57 +100,14 @@ interface ViewerContextType {
|
|||||||
triggerImmediateSpreadUpdate: (mode: SpreadMode, isDualPage?: boolean) => void;
|
triggerImmediateSpreadUpdate: (mode: SpreadMode, isDualPage?: boolean) => void;
|
||||||
|
|
||||||
// Action handlers - call EmbedPDF APIs directly
|
// Action handlers - call EmbedPDF APIs directly
|
||||||
scrollActions: {
|
scrollActions: ScrollActions;
|
||||||
scrollToPage: (page: number) => void;
|
zoomActions: ZoomActions;
|
||||||
scrollToFirstPage: () => void;
|
panActions: PanActions;
|
||||||
scrollToPreviousPage: () => void;
|
selectionActions: SelectionActions;
|
||||||
scrollToNextPage: () => void;
|
spreadActions: SpreadActions;
|
||||||
scrollToLastPage: () => void;
|
rotationActions: RotationActions;
|
||||||
};
|
searchActions: SearchActions;
|
||||||
|
exportActions: ExportActions;
|
||||||
zoomActions: {
|
|
||||||
zoomIn: () => void;
|
|
||||||
zoomOut: () => void;
|
|
||||||
toggleMarqueeZoom: () => void;
|
|
||||||
requestZoom: (level: number) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
panActions: {
|
|
||||||
enablePan: () => void;
|
|
||||||
disablePan: () => void;
|
|
||||||
togglePan: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
selectionActions: {
|
|
||||||
copyToClipboard: () => void;
|
|
||||||
getSelectedText: () => string;
|
|
||||||
getFormattedSelection: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
spreadActions: {
|
|
||||||
setSpreadMode: (mode: SpreadMode) => void;
|
|
||||||
getSpreadMode: () => SpreadMode | null;
|
|
||||||
toggleSpreadMode: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
rotationActions: {
|
|
||||||
rotateForward: () => void;
|
|
||||||
rotateBackward: () => void;
|
|
||||||
setRotation: (rotation: number) => void;
|
|
||||||
getRotation: () => number;
|
|
||||||
};
|
|
||||||
|
|
||||||
searchActions: {
|
|
||||||
search: (query: string) => Promise<void>;
|
|
||||||
next: () => void;
|
|
||||||
previous: () => void;
|
|
||||||
clear: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
exportActions: {
|
|
||||||
download: () => void;
|
|
||||||
saveAsCopy: () => Promise<ArrayBuffer | null>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bridge registration - internal use by bridges
|
// Bridge registration - internal use by bridges
|
||||||
registerBridge: (type: BridgeKey, ref: BridgeRef) => void;
|
registerBridge: (type: BridgeKey, ref: BridgeRef) => void;
|
||||||
@ -272,215 +230,21 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Action handlers - call APIs directly
|
// Action handlers - call APIs directly
|
||||||
const scrollActions = {
|
const {
|
||||||
scrollToPage: (page: number) => {
|
scrollActions,
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
zoomActions,
|
||||||
if (api?.scrollToPage) {
|
panActions,
|
||||||
api.scrollToPage({ pageNumber: page });
|
selectionActions,
|
||||||
}
|
spreadActions,
|
||||||
},
|
rotationActions,
|
||||||
scrollToFirstPage: () => {
|
searchActions,
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
exportActions,
|
||||||
if (api?.scrollToPage) {
|
} = createViewerActions({
|
||||||
api.scrollToPage({ pageNumber: 1 });
|
registry: bridgeRefs,
|
||||||
}
|
getScrollState,
|
||||||
},
|
getZoomState,
|
||||||
scrollToPreviousPage: () => {
|
triggerImmediateZoomUpdate,
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
});
|
||||||
if (api?.scrollToPreviousPage) {
|
|
||||||
api.scrollToPreviousPage();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollToNextPage: () => {
|
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
|
||||||
if (api?.scrollToNextPage) {
|
|
||||||
api.scrollToNextPage();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollToLastPage: () => {
|
|
||||||
const scrollState = getScrollState();
|
|
||||||
const api = bridgeRefs.current.scroll?.api;
|
|
||||||
if (api?.scrollToPage && scrollState.totalPages > 0) {
|
|
||||||
api.scrollToPage({ pageNumber: scrollState.totalPages });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const zoomActions = {
|
|
||||||
zoomIn: () => {
|
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
|
||||||
if (api?.zoomIn) {
|
|
||||||
const currentState = getZoomState();
|
|
||||||
const newPercent = Math.min(Math.round(currentState.zoomPercent * 1.2), 300);
|
|
||||||
triggerImmediateZoomUpdate(newPercent);
|
|
||||||
api.zoomIn();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
zoomOut: () => {
|
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
|
||||||
if (api?.zoomOut) {
|
|
||||||
const currentState = getZoomState();
|
|
||||||
const newPercent = Math.max(Math.round(currentState.zoomPercent / 1.2), 20);
|
|
||||||
triggerImmediateZoomUpdate(newPercent);
|
|
||||||
api.zoomOut();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleMarqueeZoom: () => {
|
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
|
||||||
if (api?.toggleMarqueeZoom) {
|
|
||||||
api.toggleMarqueeZoom();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestZoom: (level: number) => {
|
|
||||||
const api = bridgeRefs.current.zoom?.api;
|
|
||||||
if (api?.requestZoom) {
|
|
||||||
api.requestZoom(level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const panActions = {
|
|
||||||
enablePan: () => {
|
|
||||||
const api = bridgeRefs.current.pan?.api;
|
|
||||||
if (api?.enable) {
|
|
||||||
api.enable();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disablePan: () => {
|
|
||||||
const api = bridgeRefs.current.pan?.api;
|
|
||||||
if (api?.disable) {
|
|
||||||
api.disable();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
togglePan: () => {
|
|
||||||
const api = bridgeRefs.current.pan?.api;
|
|
||||||
if (api?.toggle) {
|
|
||||||
api.toggle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectionActions = {
|
|
||||||
copyToClipboard: () => {
|
|
||||||
const api = bridgeRefs.current.selection?.api;
|
|
||||||
if (api?.copyToClipboard) {
|
|
||||||
api.copyToClipboard();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getSelectedText: () => {
|
|
||||||
const api = bridgeRefs.current.selection?.api;
|
|
||||||
if (api?.getSelectedText) {
|
|
||||||
return api.getSelectedText();
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
},
|
|
||||||
getFormattedSelection: () => {
|
|
||||||
const api = bridgeRefs.current.selection?.api;
|
|
||||||
if (api?.getFormattedSelection) {
|
|
||||||
return api.getFormattedSelection();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const spreadActions = {
|
|
||||||
setSpreadMode: (mode: SpreadMode) => {
|
|
||||||
const api = bridgeRefs.current.spread?.api;
|
|
||||||
if (api?.setSpreadMode) {
|
|
||||||
api.setSpreadMode(mode);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getSpreadMode: () => {
|
|
||||||
const api = bridgeRefs.current.spread?.api;
|
|
||||||
if (api?.getSpreadMode) {
|
|
||||||
return api.getSpreadMode();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
toggleSpreadMode: () => {
|
|
||||||
const api = bridgeRefs.current.spread?.api;
|
|
||||||
if (api?.toggleSpreadMode) {
|
|
||||||
api.toggleSpreadMode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const rotationActions = {
|
|
||||||
rotateForward: () => {
|
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
|
||||||
if (api?.rotateForward) {
|
|
||||||
api.rotateForward();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rotateBackward: () => {
|
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
|
||||||
if (api?.rotateBackward) {
|
|
||||||
api.rotateBackward();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setRotation: (rotation: number) => {
|
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
|
||||||
if (api?.setRotation) {
|
|
||||||
api.setRotation(rotation);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getRotation: () => {
|
|
||||||
const api = bridgeRefs.current.rotation?.api;
|
|
||||||
if (api?.getRotation) {
|
|
||||||
return api.getRotation();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const searchActions = {
|
|
||||||
search: async (query: string) => {
|
|
||||||
const api = bridgeRefs.current.search?.api;
|
|
||||||
if (api?.search) {
|
|
||||||
return api.search(query);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
next: () => {
|
|
||||||
const api = bridgeRefs.current.search?.api;
|
|
||||||
if (api?.next) {
|
|
||||||
api.next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
previous: () => {
|
|
||||||
const api = bridgeRefs.current.search?.api;
|
|
||||||
if (api?.previous) {
|
|
||||||
api.previous();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clear: () => {
|
|
||||||
const api = bridgeRefs.current.search?.api;
|
|
||||||
if (api?.clear) {
|
|
||||||
api.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const exportActions = {
|
|
||||||
download: () => {
|
|
||||||
const api = bridgeRefs.current.export?.api;
|
|
||||||
if (api?.download) {
|
|
||||||
api.download();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
saveAsCopy: async () => {
|
|
||||||
const api = bridgeRefs.current.export?.api;
|
|
||||||
if (api?.saveAsCopy) {
|
|
||||||
try {
|
|
||||||
const result = api.saveAsCopy();
|
|
||||||
return await result.toPromise();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to save PDF copy:', error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const value: ViewerContextType = {
|
const value: ViewerContextType = {
|
||||||
// UI state
|
// UI state
|
||||||
|
|||||||
311
frontend/src/core/contexts/viewer/viewerActions.ts
Normal file
311
frontend/src/core/contexts/viewer/viewerActions.ts
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
import { MutableRefObject } from 'react';
|
||||||
|
import { SpreadMode } from '@embedpdf/plugin-spread/react';
|
||||||
|
import {
|
||||||
|
ViewerBridgeRegistry,
|
||||||
|
ScrollState,
|
||||||
|
ZoomState,
|
||||||
|
} from '@core/contexts/viewer/viewerBridges';
|
||||||
|
|
||||||
|
export interface ScrollActions {
|
||||||
|
scrollToPage: (page: number) => void;
|
||||||
|
scrollToFirstPage: () => void;
|
||||||
|
scrollToPreviousPage: () => void;
|
||||||
|
scrollToNextPage: () => void;
|
||||||
|
scrollToLastPage: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ZoomActions {
|
||||||
|
zoomIn: () => void;
|
||||||
|
zoomOut: () => void;
|
||||||
|
toggleMarqueeZoom: () => void;
|
||||||
|
requestZoom: (level: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PanActions {
|
||||||
|
enablePan: () => void;
|
||||||
|
disablePan: () => void;
|
||||||
|
togglePan: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectionActions {
|
||||||
|
copyToClipboard: () => void;
|
||||||
|
getSelectedText: () => string;
|
||||||
|
getFormattedSelection: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SpreadActions {
|
||||||
|
setSpreadMode: (mode: SpreadMode) => void;
|
||||||
|
getSpreadMode: () => SpreadMode | null;
|
||||||
|
toggleSpreadMode: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RotationActions {
|
||||||
|
rotateForward: () => void;
|
||||||
|
rotateBackward: () => void;
|
||||||
|
setRotation: (rotation: number) => void;
|
||||||
|
getRotation: () => number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SearchActions {
|
||||||
|
search: (query: string) => Promise<any> | undefined;
|
||||||
|
next: () => void;
|
||||||
|
previous: () => void;
|
||||||
|
clear: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExportActions {
|
||||||
|
download: () => void;
|
||||||
|
saveAsCopy: () => Promise<ArrayBuffer | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ViewerActionsBundle {
|
||||||
|
scrollActions: ScrollActions;
|
||||||
|
zoomActions: ZoomActions;
|
||||||
|
panActions: PanActions;
|
||||||
|
selectionActions: SelectionActions;
|
||||||
|
spreadActions: SpreadActions;
|
||||||
|
rotationActions: RotationActions;
|
||||||
|
searchActions: SearchActions;
|
||||||
|
exportActions: ExportActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ViewerActionDependencies {
|
||||||
|
registry: MutableRefObject<ViewerBridgeRegistry>;
|
||||||
|
getScrollState: () => ScrollState;
|
||||||
|
getZoomState: () => ZoomState;
|
||||||
|
triggerImmediateZoomUpdate: (percent: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createViewerActions({
|
||||||
|
registry,
|
||||||
|
getScrollState,
|
||||||
|
getZoomState,
|
||||||
|
triggerImmediateZoomUpdate,
|
||||||
|
}: ViewerActionDependencies): ViewerActionsBundle {
|
||||||
|
const scrollActions: ScrollActions = {
|
||||||
|
scrollToPage: (page: number) => {
|
||||||
|
const api = registry.current.scroll?.api;
|
||||||
|
if (api?.scrollToPage) {
|
||||||
|
api.scrollToPage({ pageNumber: page });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToFirstPage: () => {
|
||||||
|
const api = registry.current.scroll?.api;
|
||||||
|
if (api?.scrollToPage) {
|
||||||
|
api.scrollToPage({ pageNumber: 1 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToPreviousPage: () => {
|
||||||
|
const api = registry.current.scroll?.api;
|
||||||
|
if (api?.scrollToPreviousPage) {
|
||||||
|
api.scrollToPreviousPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToNextPage: () => {
|
||||||
|
const api = registry.current.scroll?.api;
|
||||||
|
if (api?.scrollToNextPage) {
|
||||||
|
api.scrollToNextPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToLastPage: () => {
|
||||||
|
const api = registry.current.scroll?.api;
|
||||||
|
const state = getScrollState();
|
||||||
|
if (api?.scrollToPage && state.totalPages > 0) {
|
||||||
|
api.scrollToPage({ pageNumber: state.totalPages });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoomActions: ZoomActions = {
|
||||||
|
zoomIn: () => {
|
||||||
|
const api = registry.current.zoom?.api;
|
||||||
|
if (api?.zoomIn) {
|
||||||
|
const currentState = getZoomState();
|
||||||
|
const newPercent = Math.min(
|
||||||
|
Math.round(currentState.zoomPercent * 1.2),
|
||||||
|
300
|
||||||
|
);
|
||||||
|
triggerImmediateZoomUpdate(newPercent);
|
||||||
|
api.zoomIn();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zoomOut: () => {
|
||||||
|
const api = registry.current.zoom?.api;
|
||||||
|
if (api?.zoomOut) {
|
||||||
|
const currentState = getZoomState();
|
||||||
|
const newPercent = Math.max(
|
||||||
|
Math.round(currentState.zoomPercent / 1.2),
|
||||||
|
20
|
||||||
|
);
|
||||||
|
triggerImmediateZoomUpdate(newPercent);
|
||||||
|
api.zoomOut();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggleMarqueeZoom: () => {
|
||||||
|
const api = registry.current.zoom?.api;
|
||||||
|
if (api?.toggleMarqueeZoom) {
|
||||||
|
api.toggleMarqueeZoom();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
requestZoom: (level: number) => {
|
||||||
|
const api = registry.current.zoom?.api;
|
||||||
|
if (api?.requestZoom) {
|
||||||
|
api.requestZoom(level);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const panActions: PanActions = {
|
||||||
|
enablePan: () => {
|
||||||
|
const api = registry.current.pan?.api;
|
||||||
|
if (api?.enable) {
|
||||||
|
api.enable();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disablePan: () => {
|
||||||
|
const api = registry.current.pan?.api;
|
||||||
|
if (api?.disable) {
|
||||||
|
api.disable();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
togglePan: () => {
|
||||||
|
const api = registry.current.pan?.api;
|
||||||
|
if (api?.toggle) {
|
||||||
|
api.toggle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectionActions: SelectionActions = {
|
||||||
|
copyToClipboard: () => {
|
||||||
|
const api = registry.current.selection?.api;
|
||||||
|
if (api?.copyToClipboard) {
|
||||||
|
api.copyToClipboard();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSelectedText: () => {
|
||||||
|
const api = registry.current.selection?.api;
|
||||||
|
if (api?.getSelectedText) {
|
||||||
|
return api.getSelectedText() ?? '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
getFormattedSelection: () => {
|
||||||
|
const api = registry.current.selection?.api;
|
||||||
|
if (api?.getFormattedSelection) {
|
||||||
|
return api.getFormattedSelection();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const spreadActions: SpreadActions = {
|
||||||
|
setSpreadMode: (mode: SpreadMode) => {
|
||||||
|
const api = registry.current.spread?.api;
|
||||||
|
if (api?.setSpreadMode) {
|
||||||
|
api.setSpreadMode(mode);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSpreadMode: () => {
|
||||||
|
const api = registry.current.spread?.api;
|
||||||
|
if (api?.getSpreadMode) {
|
||||||
|
return api.getSpreadMode();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
toggleSpreadMode: () => {
|
||||||
|
const api = registry.current.spread?.api;
|
||||||
|
if (api?.toggleSpreadMode) {
|
||||||
|
api.toggleSpreadMode();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const rotationActions: RotationActions = {
|
||||||
|
rotateForward: () => {
|
||||||
|
const api = registry.current.rotation?.api;
|
||||||
|
if (api?.rotateForward) {
|
||||||
|
api.rotateForward();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rotateBackward: () => {
|
||||||
|
const api = registry.current.rotation?.api;
|
||||||
|
if (api?.rotateBackward) {
|
||||||
|
api.rotateBackward();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setRotation: (rotation: number) => {
|
||||||
|
const api = registry.current.rotation?.api;
|
||||||
|
if (api?.setRotation) {
|
||||||
|
api.setRotation(rotation);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getRotation: () => {
|
||||||
|
const api = registry.current.rotation?.api;
|
||||||
|
if (api?.getRotation) {
|
||||||
|
return api.getRotation();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchActions: SearchActions = {
|
||||||
|
search: (query: string) => {
|
||||||
|
const api = registry.current.search?.api;
|
||||||
|
if (api?.search) {
|
||||||
|
return api.search(query);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
next: () => {
|
||||||
|
const api = registry.current.search?.api;
|
||||||
|
if (api?.next) {
|
||||||
|
api.next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
previous: () => {
|
||||||
|
const api = registry.current.search?.api;
|
||||||
|
if (api?.previous) {
|
||||||
|
api.previous();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear: () => {
|
||||||
|
const api = registry.current.search?.api;
|
||||||
|
if (api?.clear) {
|
||||||
|
api.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportActions: ExportActions = {
|
||||||
|
download: () => {
|
||||||
|
const api = registry.current.export?.api;
|
||||||
|
if (api?.download) {
|
||||||
|
api.download();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
saveAsCopy: async () => {
|
||||||
|
const api = registry.current.export?.api;
|
||||||
|
if (api?.saveAsCopy) {
|
||||||
|
try {
|
||||||
|
const result = api.saveAsCopy();
|
||||||
|
return await result.toPromise();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to save PDF copy:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrollActions,
|
||||||
|
zoomActions,
|
||||||
|
panActions,
|
||||||
|
selectionActions,
|
||||||
|
spreadActions,
|
||||||
|
rotationActions,
|
||||||
|
searchActions,
|
||||||
|
exportActions,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user