mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 01:19:24 +00:00
Restructure to avoid global variables
fix zoom
This commit is contained in:
parent
b81ed9ec2e
commit
41e5a7fbd6
@ -28,7 +28,11 @@ const EmbedPdfViewerContent = ({
|
||||
const { colorScheme } = useMantineColorScheme();
|
||||
const viewerRef = React.useRef<HTMLDivElement>(null);
|
||||
const [isViewerHovered, setIsViewerHovered] = React.useState(false);
|
||||
const { isThumbnailSidebarVisible, toggleThumbnailSidebar, zoomActions, spreadActions, panActions: _panActions, rotationActions: _rotationActions } = useViewer();
|
||||
const { isThumbnailSidebarVisible, toggleThumbnailSidebar, zoomActions, spreadActions, panActions: _panActions, rotationActions: _rotationActions, getScrollState, getZoomState, getSpreadState } = useViewer();
|
||||
|
||||
const scrollState = getScrollState();
|
||||
const zoomState = getZoomState();
|
||||
const spreadState = getSpreadState();
|
||||
|
||||
|
||||
// Get current file from FileContext
|
||||
@ -71,28 +75,13 @@ const EmbedPdfViewerContent = ({
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (event.deltaY < 0) {
|
||||
// Scroll up - zoom in
|
||||
zoomActions.zoomIn();
|
||||
} else {
|
||||
// Scroll down - zoom out
|
||||
zoomActions.zoomOut();
|
||||
=======
|
||||
// Convert smooth scrolling gestures into discrete notches
|
||||
accumulator += event.deltaY;
|
||||
const threshold = 10;
|
||||
|
||||
const zoomAPI = window.embedPdfZoom;
|
||||
if (zoomAPI) {
|
||||
if (accumulator <= -threshold) {
|
||||
zoomAPI.zoomIn();
|
||||
accumulator = 0;
|
||||
} else if (accumulator >= threshold) {
|
||||
zoomAPI.zoomOut();
|
||||
accumulator = 0;
|
||||
}
|
||||
>>>>>>> 81c5d8ff46dcc5fc983109fb2348b6d6dfb129d2
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -131,17 +120,6 @@ const EmbedPdfViewerContent = ({
|
||||
};
|
||||
}, [isViewerHovered]);
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// Expose toggle functions globally for right rail buttons
|
||||
React.useEffect(() => {
|
||||
window.toggleThumbnailSidebar = toggleThumbnailSidebar;
|
||||
|
||||
return () => {
|
||||
delete window.toggleThumbnailSidebar;
|
||||
};
|
||||
}, [toggleThumbnailSidebar]);
|
||||
>>>>>>> 81c5d8ff46dcc5fc983109fb2348b6d6dfb129d2
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -220,17 +198,17 @@ const EmbedPdfViewerContent = ({
|
||||
>
|
||||
<div style={{ pointerEvents: "auto" }}>
|
||||
<PdfViewerToolbar
|
||||
currentPage={1}
|
||||
totalPages={1}
|
||||
currentPage={scrollState.currentPage}
|
||||
totalPages={scrollState.totalPages}
|
||||
onPageChange={(page) => {
|
||||
// Placeholder - will implement page navigation later
|
||||
console.log('Navigate to page:', page);
|
||||
}}
|
||||
dualPage={false}
|
||||
dualPage={spreadState.isDualPage}
|
||||
onDualPageToggle={() => {
|
||||
spreadActions.toggleSpreadMode();
|
||||
}}
|
||||
currentZoom={100}
|
||||
currentZoom={zoomState.zoomPercent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -231,16 +231,13 @@ export function LocalEmbedPDF({ file, url, colorScheme }: LocalEmbedPDFProps) {
|
||||
onDrop={(e) => e.preventDefault()}
|
||||
onDragOver={(e) => e.preventDefault()}
|
||||
>
|
||||
{/* 1. Low-resolution base layer for immediate feedback */}
|
||||
<RenderLayer pageIndex={pageIndex} scale={0.5} />
|
||||
|
||||
{/* 2. High-resolution tile layer on top */}
|
||||
{/* High-resolution tile layer */}
|
||||
<TilingLayer pageIndex={pageIndex} scale={scale} />
|
||||
|
||||
{/* 3. Search highlight layer */}
|
||||
{/* Search highlight layer */}
|
||||
<CustomSearchLayer pageIndex={pageIndex} scale={scale} />
|
||||
|
||||
{/* 4. Selection layer for text interaction */}
|
||||
{/* Selection layer for text interaction */}
|
||||
<SelectionLayer pageIndex={pageIndex} scale={scale} />
|
||||
</div>
|
||||
</PagePointerProvider>
|
||||
|
@ -39,7 +39,7 @@ export function PanAPIBridge() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [pan, isPanning, registerBridge]);
|
||||
}, [pan, isPanning]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -33,17 +33,24 @@ export function PdfViewerToolbar({
|
||||
currentZoom: _currentZoom = 100,
|
||||
}: PdfViewerToolbarProps) {
|
||||
const { t } = useTranslation();
|
||||
const { getScrollState, getZoomState, scrollActions, zoomActions } = useViewer();
|
||||
const { getScrollState, getZoomState, scrollActions, zoomActions, registerImmediateZoomUpdate } = useViewer();
|
||||
|
||||
const scrollState = getScrollState();
|
||||
const zoomState = getZoomState();
|
||||
const [pageInput, setPageInput] = useState(scrollState.currentPage || currentPage);
|
||||
const [displayZoomPercent, setDisplayZoomPercent] = useState(zoomState.zoomPercent || 140);
|
||||
|
||||
// Update page input when scroll state changes
|
||||
useEffect(() => {
|
||||
setPageInput(scrollState.currentPage);
|
||||
}, [scrollState.currentPage]);
|
||||
|
||||
// Register for immediate zoom updates and sync with actual zoom state
|
||||
useEffect(() => {
|
||||
registerImmediateZoomUpdate(setDisplayZoomPercent);
|
||||
setDisplayZoomPercent(zoomState.zoomPercent || 140);
|
||||
}, [zoomState.zoomPercent, registerImmediateZoomUpdate]);
|
||||
|
||||
const handleZoomOut = () => {
|
||||
zoomActions.zoomOut();
|
||||
};
|
||||
@ -204,7 +211,7 @@ export function PdfViewerToolbar({
|
||||
−
|
||||
</Button>
|
||||
<span style={{ minWidth: '2.5rem', textAlign: "center" }}>
|
||||
{zoomState.zoomPercent}%
|
||||
{displayZoomPercent}%
|
||||
</span>
|
||||
<Button
|
||||
variant="subtle"
|
||||
|
@ -33,7 +33,7 @@ export function RotateAPIBridge() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [rotate, rotation, registerBridge]);
|
||||
}, [rotate, rotation]);
|
||||
|
||||
return null;
|
||||
}
|
@ -21,14 +21,21 @@ export function ScrollAPIBridge() {
|
||||
currentPage: scrollState.currentPage,
|
||||
totalPages: scrollState.totalPages,
|
||||
};
|
||||
setLocalState(newState);
|
||||
|
||||
setLocalState(prevState => {
|
||||
// Only update if state actually changed
|
||||
if (prevState.currentPage !== newState.currentPage || prevState.totalPages !== newState.totalPages) {
|
||||
return newState;
|
||||
}
|
||||
return prevState;
|
||||
});
|
||||
|
||||
registerBridge('scroll', {
|
||||
state: newState,
|
||||
api: scroll
|
||||
});
|
||||
}
|
||||
}, [scroll, scrollState, registerBridge]);
|
||||
}, [scroll, scrollState]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -20,9 +20,17 @@ export function SearchAPIBridge() {
|
||||
if (!search) return;
|
||||
|
||||
const unsubscribe = search.onSearchResultStateChange?.((state: any) => {
|
||||
setLocalState({
|
||||
const newState = {
|
||||
results: state?.results || null,
|
||||
activeIndex: (state?.activeResultIndex || 0) + 1 // Convert to 1-based index
|
||||
};
|
||||
|
||||
setLocalState(prevState => {
|
||||
// Only update if state actually changed
|
||||
if (prevState.results !== newState.results || prevState.activeIndex !== newState.activeIndex) {
|
||||
return newState;
|
||||
}
|
||||
return prevState;
|
||||
});
|
||||
});
|
||||
|
||||
@ -49,7 +57,7 @@ export function SearchAPIBridge() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [search, localState, registerBridge]);
|
||||
}, [search, localState]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ export function SelectionAPIBridge() {
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}
|
||||
}, [selection, hasSelection, registerBridge]);
|
||||
}, [selection, hasSelection]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export function SpreadAPIBridge() {
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [spread, spreadMode, registerBridge]);
|
||||
}, [spread, spreadMode]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export function ThumbnailAPIBridge() {
|
||||
api: thumbnail
|
||||
});
|
||||
}
|
||||
}, [thumbnail, registerBridge]);
|
||||
}, [thumbnail]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export function ZoomAPIBridge() {
|
||||
const { provides: zoom, state: zoomState } = useZoom();
|
||||
const { registerBridge } = useViewer();
|
||||
const hasSetInitialZoom = useRef(false);
|
||||
|
||||
|
||||
// Store state locally
|
||||
const [_localState, setLocalState] = useState({
|
||||
currentZoom: 1.4,
|
||||
@ -30,10 +30,14 @@ export function ZoomAPIBridge() {
|
||||
useEffect(() => {
|
||||
if (zoom && zoomState) {
|
||||
// Update local state
|
||||
const currentZoomLevel = zoomState.currentZoomLevel || 1.4;
|
||||
const newState = {
|
||||
currentZoom: zoomState.currentZoomLevel || 1.4,
|
||||
zoomPercent: Math.round((zoomState.currentZoomLevel || 1.4) * 100),
|
||||
currentZoom: currentZoomLevel,
|
||||
zoomPercent: Math.round(currentZoomLevel * 100),
|
||||
};
|
||||
|
||||
console.log('ZoomAPIBridge - Raw zoom level:', currentZoomLevel, 'Rounded percent:', newState.zoomPercent);
|
||||
|
||||
setLocalState(newState);
|
||||
|
||||
// Register this bridge with ViewerContext
|
||||
@ -42,7 +46,7 @@ export function ZoomAPIBridge() {
|
||||
api: zoom
|
||||
});
|
||||
}
|
||||
}, [zoom, zoomState, registerBridge]);
|
||||
}, [zoom, zoomState]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -59,6 +59,9 @@ interface ViewerContextType {
|
||||
getSearchActiveIndex: () => number;
|
||||
getThumbnailAPI: () => any;
|
||||
|
||||
// Immediate update callbacks
|
||||
registerImmediateZoomUpdate: (callback: (percent: number) => void) => void;
|
||||
|
||||
// Action handlers - call EmbedPDF APIs directly
|
||||
scrollActions: {
|
||||
scrollToPage: (page: number) => void;
|
||||
@ -133,6 +136,9 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
||||
thumbnail: null as BridgeRef | null,
|
||||
});
|
||||
|
||||
// Immediate zoom callback for responsive display updates
|
||||
const immediateZoomUpdateCallback = useRef<((percent: number) => void) | null>(null);
|
||||
|
||||
const registerBridge = (type: string, ref: BridgeRef) => {
|
||||
bridgeRefs.current[type as keyof typeof bridgeRefs.current] = ref;
|
||||
};
|
||||
@ -217,12 +223,24 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
||||
zoomIn: () => {
|
||||
const api = bridgeRefs.current.zoom?.api;
|
||||
if (api?.zoomIn) {
|
||||
// Update display immediately if callback is registered
|
||||
if (immediateZoomUpdateCallback.current) {
|
||||
const currentState = getZoomState();
|
||||
const newPercent = Math.min(Math.round(currentState.zoomPercent * 1.2), 300);
|
||||
immediateZoomUpdateCallback.current(newPercent);
|
||||
}
|
||||
api.zoomIn();
|
||||
}
|
||||
},
|
||||
zoomOut: () => {
|
||||
const api = bridgeRefs.current.zoom?.api;
|
||||
if (api?.zoomOut) {
|
||||
// Update display immediately if callback is registered
|
||||
if (immediateZoomUpdateCallback.current) {
|
||||
const currentState = getZoomState();
|
||||
const newPercent = Math.max(Math.round(currentState.zoomPercent / 1.2), 20);
|
||||
immediateZoomUpdateCallback.current(newPercent);
|
||||
}
|
||||
api.zoomOut();
|
||||
}
|
||||
},
|
||||
@ -361,6 +379,10 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const registerImmediateZoomUpdate = (callback: (percent: number) => void) => {
|
||||
immediateZoomUpdateCallback.current = callback;
|
||||
};
|
||||
|
||||
const value: ViewerContextType = {
|
||||
// UI state
|
||||
isThumbnailSidebarVisible,
|
||||
@ -377,6 +399,9 @@ export const ViewerProvider: React.FC<ViewerProviderProps> = ({ children }) => {
|
||||
getSearchActiveIndex,
|
||||
getThumbnailAPI,
|
||||
|
||||
// Immediate updates
|
||||
registerImmediateZoomUpdate,
|
||||
|
||||
// Actions
|
||||
scrollActions,
|
||||
zoomActions,
|
||||
|
Loading…
x
Reference in New Issue
Block a user