Skip to content

Commit e401e29

Browse files
committed
Fix issue with bookmarks
1 parent f13b2d4 commit e401e29

1 file changed

Lines changed: 64 additions & 34 deletions

File tree

viewers/snippet/src/components/outline-sidebar.tsx

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@ import { useState, useEffect } from 'preact/hooks';
33
import { useBookmarkCapability } from '@embedpdf/plugin-bookmark/preact';
44
import { useScrollCapability } from '@embedpdf/plugin-scroll/preact';
55
import { useTranslations } from '@embedpdf/plugin-i18n/preact';
6-
import { PdfBookmarkObject, PdfZoomMode, PdfErrorCode, ignore } from '@embedpdf/models';
6+
import {
7+
PdfBookmarkObject,
8+
PdfZoomMode,
9+
PdfErrorCode,
10+
ignore,
11+
PdfActionType,
12+
PdfDestinationObject,
13+
} from '@embedpdf/models';
714
import { useDocumentState } from '@embedpdf/core/preact';
815
import { Icon } from './ui/icon';
916
import { ChevronDownIcon } from './icons/chevron-down';
@@ -20,16 +27,25 @@ export function OutlineSidebar({ documentId }: OutlineSidebarProps) {
2027
const documentState = useDocumentState(documentId);
2128
const [bookmarks, setBookmarks] = useState<PdfBookmarkObject[]>([]);
2229
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
30+
const [isLoading, setIsLoading] = useState(true);
2331

2432
useEffect(() => {
2533
if (!bookmark || !documentState?.document) return;
34+
35+
setIsLoading(true);
2636
const task = bookmark.getBookmarks();
27-
task.wait(({ bookmarks }) => {
28-
setBookmarks(bookmarks);
29-
// Auto-expand first level items
30-
const firstLevelIds = bookmarks.map((_, index) => `bookmark-${index}`);
31-
setExpandedItems(new Set(firstLevelIds));
32-
}, ignore);
37+
task.wait(
38+
({ bookmarks }) => {
39+
setBookmarks(bookmarks);
40+
// Auto-expand first level items
41+
const firstLevelIds = bookmarks.map((_, index) => `bookmark-${index}`);
42+
setExpandedItems(new Set(firstLevelIds));
43+
setIsLoading(false);
44+
},
45+
() => {
46+
setIsLoading(false);
47+
},
48+
);
3349

3450
return () => {
3551
task.abort({
@@ -40,33 +56,47 @@ export function OutlineSidebar({ documentId }: OutlineSidebarProps) {
4056
}, [bookmark, documentState?.document]);
4157

4258
const handleBookmarkClick = (bookmark: PdfBookmarkObject) => {
43-
if (!scroll || !bookmark.target || bookmark.target.type !== 'action') return;
44-
45-
const action = bookmark.target.action;
46-
if (action.type === 1 && action.destination) {
47-
// Type 1 is "Go to destination"
48-
const destination = action.destination;
49-
50-
if (destination.zoom.mode === PdfZoomMode.XYZ) {
51-
const page = documentState?.document?.pages.find((p) => p.index === destination.pageIndex);
52-
if (!page) return;
53-
54-
scroll.scrollToPage({
55-
pageNumber: destination.pageIndex + 1,
56-
pageCoordinates: destination.zoom.params
57-
? {
58-
x: destination.zoom.params.x,
59-
y: page.size.height - destination.zoom.params.y,
60-
}
61-
: undefined,
62-
behavior: 'smooth',
63-
});
64-
} else if (destination.zoom.mode === PdfZoomMode.FitPage) {
65-
scroll.scrollToPage({
66-
pageNumber: destination.pageIndex + 1,
67-
behavior: 'smooth',
68-
});
59+
if (!scroll || !bookmark.target) return;
60+
61+
// Extract destination from either action or direct destination target
62+
let destination: PdfDestinationObject | undefined;
63+
64+
if (bookmark.target.type === 'action') {
65+
const action = bookmark.target.action;
66+
if (action.type === PdfActionType.Goto || action.type === PdfActionType.RemoteGoto) {
67+
destination = action.destination;
68+
} else if (action.type === PdfActionType.URI) {
69+
// Open URI in new tab
70+
window.open(action.uri, '_blank');
71+
return;
6972
}
73+
// Other action types (Unsupported, LaunchAppOrOpenFile) are not handled
74+
} else if (bookmark.target.type === 'destination') {
75+
destination = bookmark.target.destination;
76+
}
77+
78+
if (!destination) return;
79+
80+
if (destination.zoom.mode === PdfZoomMode.XYZ) {
81+
const page = documentState?.document?.pages.find((p) => p.index === destination.pageIndex);
82+
if (!page) return;
83+
84+
scroll.scrollToPage({
85+
pageNumber: destination.pageIndex + 1,
86+
pageCoordinates: destination.zoom.params
87+
? {
88+
x: destination.zoom.params.x,
89+
y: page.size.height - destination.zoom.params.y,
90+
}
91+
: undefined,
92+
behavior: 'smooth',
93+
});
94+
} else {
95+
// Handle FitPage, FitH, FitV, FitR, FitB, FitBH, FitBV, etc.
96+
scroll.scrollToPage({
97+
pageNumber: destination.pageIndex + 1,
98+
behavior: 'smooth',
99+
});
70100
}
71101
};
72102

@@ -127,7 +157,7 @@ export function OutlineSidebar({ documentId }: OutlineSidebarProps) {
127157
);
128158
};
129159

130-
if (!documentState?.document) {
160+
if (!documentState?.document || isLoading) {
131161
return (
132162
<div className="text-fg-secondary flex h-full flex-col gap-3 p-4 text-sm">
133163
<div className="text-fg-primary font-medium">{translate('outline.title')}</div>

0 commit comments

Comments
 (0)