pdfjs-reader-core 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +950 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +408 -6
- package/dist/index.d.ts +408 -6
- package/dist/index.js +929 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -332,6 +332,9 @@ var init_highlight_storage = __esm({
|
|
|
332
332
|
});
|
|
333
333
|
|
|
334
334
|
// src/store/viewer-store.ts
|
|
335
|
+
function generateRequestId() {
|
|
336
|
+
return `scroll-${Date.now()}-${++requestCounter}`;
|
|
337
|
+
}
|
|
335
338
|
function createViewerStore(initialOverrides = {}) {
|
|
336
339
|
return (0, import_vanilla.createStore)()((set, get) => ({
|
|
337
340
|
...initialState,
|
|
@@ -384,6 +387,46 @@ function createViewerStore(initialOverrides = {}) {
|
|
|
384
387
|
set({ currentPage: currentPage - 1 });
|
|
385
388
|
}
|
|
386
389
|
},
|
|
390
|
+
// Scroll coordination actions
|
|
391
|
+
requestScrollToPage: (page, behavior = "smooth") => {
|
|
392
|
+
const { numPages } = get();
|
|
393
|
+
const validPage = Math.max(1, Math.min(page, numPages));
|
|
394
|
+
return new Promise((resolve) => {
|
|
395
|
+
const requestId = generateRequestId();
|
|
396
|
+
const timeoutId = setTimeout(() => {
|
|
397
|
+
const callback = scrollCallbacks.get(requestId);
|
|
398
|
+
if (callback) {
|
|
399
|
+
scrollCallbacks.delete(requestId);
|
|
400
|
+
callback.resolve();
|
|
401
|
+
}
|
|
402
|
+
const currentRequest = get().scrollToPageRequest;
|
|
403
|
+
if (currentRequest?.requestId === requestId) {
|
|
404
|
+
set({ scrollToPageRequest: null });
|
|
405
|
+
}
|
|
406
|
+
}, SCROLL_TIMEOUT_MS);
|
|
407
|
+
scrollCallbacks.set(requestId, { resolve, timeoutId });
|
|
408
|
+
set({
|
|
409
|
+
currentPage: validPage,
|
|
410
|
+
scrollToPageRequest: {
|
|
411
|
+
page: validPage,
|
|
412
|
+
requestId,
|
|
413
|
+
behavior
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
},
|
|
418
|
+
completeScrollRequest: (requestId) => {
|
|
419
|
+
const callback = scrollCallbacks.get(requestId);
|
|
420
|
+
if (callback) {
|
|
421
|
+
clearTimeout(callback.timeoutId);
|
|
422
|
+
scrollCallbacks.delete(requestId);
|
|
423
|
+
callback.resolve();
|
|
424
|
+
}
|
|
425
|
+
const currentRequest = get().scrollToPageRequest;
|
|
426
|
+
if (currentRequest?.requestId === requestId) {
|
|
427
|
+
set({ scrollToPageRequest: null });
|
|
428
|
+
}
|
|
429
|
+
},
|
|
387
430
|
// Zoom actions
|
|
388
431
|
setScale: (scale) => {
|
|
389
432
|
const clampedScale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
|
|
@@ -450,7 +493,7 @@ function createViewerStore(initialOverrides = {}) {
|
|
|
450
493
|
}
|
|
451
494
|
}));
|
|
452
495
|
}
|
|
453
|
-
var import_vanilla, ZOOM_LEVELS, MIN_SCALE, MAX_SCALE, initialState;
|
|
496
|
+
var import_vanilla, ZOOM_LEVELS, MIN_SCALE, MAX_SCALE, SCROLL_TIMEOUT_MS, scrollCallbacks, requestCounter, initialState;
|
|
454
497
|
var init_viewer_store = __esm({
|
|
455
498
|
"src/store/viewer-store.ts"() {
|
|
456
499
|
"use strict";
|
|
@@ -458,6 +501,9 @@ var init_viewer_store = __esm({
|
|
|
458
501
|
ZOOM_LEVELS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 3, 4];
|
|
459
502
|
MIN_SCALE = 0.1;
|
|
460
503
|
MAX_SCALE = 10;
|
|
504
|
+
SCROLL_TIMEOUT_MS = 3e3;
|
|
505
|
+
scrollCallbacks = /* @__PURE__ */ new Map();
|
|
506
|
+
requestCounter = 0;
|
|
461
507
|
initialState = {
|
|
462
508
|
// Document state
|
|
463
509
|
document: null,
|
|
@@ -468,6 +514,8 @@ var init_viewer_store = __esm({
|
|
|
468
514
|
currentPage: 1,
|
|
469
515
|
scale: 1,
|
|
470
516
|
rotation: 0,
|
|
517
|
+
// Scroll coordination
|
|
518
|
+
scrollToPageRequest: null,
|
|
471
519
|
// UI state
|
|
472
520
|
viewMode: "single",
|
|
473
521
|
scrollMode: "single",
|
|
@@ -1277,6 +1325,252 @@ var init_agent_api = __esm({
|
|
|
1277
1325
|
}
|
|
1278
1326
|
});
|
|
1279
1327
|
|
|
1328
|
+
// src/utils/text-search.ts
|
|
1329
|
+
async function extractPageText(document2, pageNumber) {
|
|
1330
|
+
const page = await document2.getPage(pageNumber);
|
|
1331
|
+
const textContent = await page.getTextContent();
|
|
1332
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
1333
|
+
let fullText = "";
|
|
1334
|
+
const charPositions = [];
|
|
1335
|
+
for (const item of textContent.items) {
|
|
1336
|
+
if ("str" in item && item.str) {
|
|
1337
|
+
const tx = item.transform;
|
|
1338
|
+
const x = tx[4];
|
|
1339
|
+
const y = viewport.height - tx[5];
|
|
1340
|
+
const width = item.width ?? 0;
|
|
1341
|
+
const height = item.height ?? 12;
|
|
1342
|
+
const charWidth = item.str.length > 0 ? width / item.str.length : width;
|
|
1343
|
+
for (let i = 0; i < item.str.length; i++) {
|
|
1344
|
+
charPositions.push({
|
|
1345
|
+
char: item.str[i],
|
|
1346
|
+
rect: {
|
|
1347
|
+
x: x + i * charWidth,
|
|
1348
|
+
y: y - height,
|
|
1349
|
+
width: charWidth,
|
|
1350
|
+
height
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
fullText += item.str;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return { fullText, charPositions };
|
|
1358
|
+
}
|
|
1359
|
+
async function findTextOnPage(document2, pageNumber, query, options = {}) {
|
|
1360
|
+
const { caseSensitive = false, wholeWord = false } = options;
|
|
1361
|
+
if (!query || pageNumber < 1 || pageNumber > document2.numPages) {
|
|
1362
|
+
return [];
|
|
1363
|
+
}
|
|
1364
|
+
const { fullText, charPositions } = await extractPageText(document2, pageNumber);
|
|
1365
|
+
const matches = [];
|
|
1366
|
+
const searchText = caseSensitive ? query : query.toLowerCase();
|
|
1367
|
+
const textToSearch = caseSensitive ? fullText : fullText.toLowerCase();
|
|
1368
|
+
let startIndex = 0;
|
|
1369
|
+
while (true) {
|
|
1370
|
+
const matchIndex = textToSearch.indexOf(searchText, startIndex);
|
|
1371
|
+
if (matchIndex === -1) break;
|
|
1372
|
+
if (wholeWord) {
|
|
1373
|
+
const beforeChar = matchIndex > 0 ? textToSearch[matchIndex - 1] : " ";
|
|
1374
|
+
const afterChar = matchIndex + query.length < textToSearch.length ? textToSearch[matchIndex + query.length] : " ";
|
|
1375
|
+
if (/\w/.test(beforeChar) || /\w/.test(afterChar)) {
|
|
1376
|
+
startIndex = matchIndex + 1;
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
const matchRects = [];
|
|
1381
|
+
for (let i = matchIndex; i < matchIndex + query.length && i < charPositions.length; i++) {
|
|
1382
|
+
matchRects.push(charPositions[i].rect);
|
|
1383
|
+
}
|
|
1384
|
+
const mergedRects = mergeAdjacentRects(matchRects);
|
|
1385
|
+
matches.push({
|
|
1386
|
+
text: fullText.substring(matchIndex, matchIndex + query.length),
|
|
1387
|
+
rects: mergedRects,
|
|
1388
|
+
pageNumber,
|
|
1389
|
+
startIndex: matchIndex
|
|
1390
|
+
});
|
|
1391
|
+
startIndex = matchIndex + 1;
|
|
1392
|
+
}
|
|
1393
|
+
return matches;
|
|
1394
|
+
}
|
|
1395
|
+
async function findTextInDocument(document2, query, options = {}) {
|
|
1396
|
+
const { pageRange, ...findOptions } = options;
|
|
1397
|
+
const pagesToSearch = pageRange ?? Array.from({ length: document2.numPages }, (_, i) => i + 1);
|
|
1398
|
+
const allMatches = [];
|
|
1399
|
+
for (const pageNum of pagesToSearch) {
|
|
1400
|
+
if (pageNum < 1 || pageNum > document2.numPages) continue;
|
|
1401
|
+
try {
|
|
1402
|
+
const matches = await findTextOnPage(document2, pageNum, query, findOptions);
|
|
1403
|
+
allMatches.push(...matches);
|
|
1404
|
+
} catch {
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return allMatches;
|
|
1408
|
+
}
|
|
1409
|
+
function mergeAdjacentRects(rects) {
|
|
1410
|
+
if (rects.length === 0) return [];
|
|
1411
|
+
const sorted = [...rects].sort((a, b) => a.y - b.y || a.x - b.x);
|
|
1412
|
+
const merged = [];
|
|
1413
|
+
let current = { ...sorted[0] };
|
|
1414
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
1415
|
+
const rect = sorted[i];
|
|
1416
|
+
if (Math.abs(rect.y - current.y) < 2 && rect.x <= current.x + current.width + 2) {
|
|
1417
|
+
const newRight = Math.max(current.x + current.width, rect.x + rect.width);
|
|
1418
|
+
current.width = newRight - current.x;
|
|
1419
|
+
current.height = Math.max(current.height, rect.height);
|
|
1420
|
+
} else {
|
|
1421
|
+
merged.push(current);
|
|
1422
|
+
current = { ...rect };
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
merged.push(current);
|
|
1426
|
+
return merged;
|
|
1427
|
+
}
|
|
1428
|
+
async function getPageText(document2, pageNumber) {
|
|
1429
|
+
if (pageNumber < 1 || pageNumber > document2.numPages) {
|
|
1430
|
+
return "";
|
|
1431
|
+
}
|
|
1432
|
+
const page = await document2.getPage(pageNumber);
|
|
1433
|
+
const textContent = await page.getTextContent();
|
|
1434
|
+
return textContent.items.filter((item) => "str" in item).map((item) => item.str).join("");
|
|
1435
|
+
}
|
|
1436
|
+
async function countTextOnPage(document2, pageNumber, query, options = {}) {
|
|
1437
|
+
const { caseSensitive = false, wholeWord = false } = options;
|
|
1438
|
+
if (!query || pageNumber < 1 || pageNumber > document2.numPages) {
|
|
1439
|
+
return 0;
|
|
1440
|
+
}
|
|
1441
|
+
const text = await getPageText(document2, pageNumber);
|
|
1442
|
+
const searchText = caseSensitive ? query : query.toLowerCase();
|
|
1443
|
+
const textToSearch = caseSensitive ? text : text.toLowerCase();
|
|
1444
|
+
let count = 0;
|
|
1445
|
+
let startIndex = 0;
|
|
1446
|
+
while (true) {
|
|
1447
|
+
const matchIndex = textToSearch.indexOf(searchText, startIndex);
|
|
1448
|
+
if (matchIndex === -1) break;
|
|
1449
|
+
if (wholeWord) {
|
|
1450
|
+
const beforeChar = matchIndex > 0 ? textToSearch[matchIndex - 1] : " ";
|
|
1451
|
+
const afterChar = matchIndex + query.length < textToSearch.length ? textToSearch[matchIndex + query.length] : " ";
|
|
1452
|
+
if (/\w/.test(beforeChar) || /\w/.test(afterChar)) {
|
|
1453
|
+
startIndex = matchIndex + 1;
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
count++;
|
|
1458
|
+
startIndex = matchIndex + 1;
|
|
1459
|
+
}
|
|
1460
|
+
return count;
|
|
1461
|
+
}
|
|
1462
|
+
var init_text_search = __esm({
|
|
1463
|
+
"src/utils/text-search.ts"() {
|
|
1464
|
+
"use strict";
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
// src/utils/coordinates.ts
|
|
1469
|
+
function pdfToViewport(x, y, scale, pageHeight) {
|
|
1470
|
+
return {
|
|
1471
|
+
x: x * scale,
|
|
1472
|
+
y: (pageHeight - y) * scale
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
function viewportToPDF(x, y, scale, pageHeight) {
|
|
1476
|
+
return {
|
|
1477
|
+
x: x / scale,
|
|
1478
|
+
y: pageHeight - y / scale
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
function percentToPDF(xPercent, yPercent, pageWidth, pageHeight) {
|
|
1482
|
+
return {
|
|
1483
|
+
x: xPercent / 100 * pageWidth,
|
|
1484
|
+
y: yPercent / 100 * pageHeight
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
function pdfToPercent(x, y, pageWidth, pageHeight) {
|
|
1488
|
+
return {
|
|
1489
|
+
x: x / pageWidth * 100,
|
|
1490
|
+
y: y / pageHeight * 100
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
function percentToViewport(xPercent, yPercent, pageWidth, pageHeight, scale) {
|
|
1494
|
+
return {
|
|
1495
|
+
x: xPercent / 100 * pageWidth * scale,
|
|
1496
|
+
y: yPercent / 100 * pageHeight * scale
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
function viewportToPercent(x, y, pageWidth, pageHeight, scale) {
|
|
1500
|
+
return {
|
|
1501
|
+
x: x / (pageWidth * scale) * 100,
|
|
1502
|
+
y: y / (pageHeight * scale) * 100
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
function applyRotation(x, y, rotation, pageWidth, pageHeight) {
|
|
1506
|
+
const normalizedRotation = (rotation % 360 + 360) % 360;
|
|
1507
|
+
switch (normalizedRotation) {
|
|
1508
|
+
case 90:
|
|
1509
|
+
return { x: y, y: pageWidth - x };
|
|
1510
|
+
case 180:
|
|
1511
|
+
return { x: pageWidth - x, y: pageHeight - y };
|
|
1512
|
+
case 270:
|
|
1513
|
+
return { x: pageHeight - y, y: x };
|
|
1514
|
+
default:
|
|
1515
|
+
return { x, y };
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
function removeRotation(x, y, rotation, pageWidth, pageHeight) {
|
|
1519
|
+
const normalizedRotation = (rotation % 360 + 360) % 360;
|
|
1520
|
+
switch (normalizedRotation) {
|
|
1521
|
+
case 90:
|
|
1522
|
+
return { x: pageWidth - y, y: x };
|
|
1523
|
+
case 180:
|
|
1524
|
+
return { x: pageWidth - x, y: pageHeight - y };
|
|
1525
|
+
case 270:
|
|
1526
|
+
return { x: y, y: pageHeight - x };
|
|
1527
|
+
default:
|
|
1528
|
+
return { x, y };
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
function getRotatedDimensions(width, height, rotation) {
|
|
1532
|
+
const normalizedRotation = (rotation % 360 + 360) % 360;
|
|
1533
|
+
if (normalizedRotation === 90 || normalizedRotation === 270) {
|
|
1534
|
+
return { width: height, height: width };
|
|
1535
|
+
}
|
|
1536
|
+
return { width, height };
|
|
1537
|
+
}
|
|
1538
|
+
function scaleRect(rect, fromScale, toScale) {
|
|
1539
|
+
const ratio = toScale / fromScale;
|
|
1540
|
+
return {
|
|
1541
|
+
x: rect.x * ratio,
|
|
1542
|
+
y: rect.y * ratio,
|
|
1543
|
+
width: rect.width * ratio,
|
|
1544
|
+
height: rect.height * ratio
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
function isPointInRect(point, rect) {
|
|
1548
|
+
return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height;
|
|
1549
|
+
}
|
|
1550
|
+
function doRectsIntersect(rectA, rectB) {
|
|
1551
|
+
return !(rectA.x + rectA.width < rectB.x || rectB.x + rectB.width < rectA.x || rectA.y + rectA.height < rectB.y || rectB.y + rectB.height < rectA.y);
|
|
1552
|
+
}
|
|
1553
|
+
function getRectIntersection(rectA, rectB) {
|
|
1554
|
+
const x = Math.max(rectA.x, rectB.x);
|
|
1555
|
+
const y = Math.max(rectA.y, rectB.y);
|
|
1556
|
+
const right = Math.min(rectA.x + rectA.width, rectB.x + rectB.width);
|
|
1557
|
+
const bottom = Math.min(rectA.y + rectA.height, rectB.y + rectB.height);
|
|
1558
|
+
if (right <= x || bottom <= y) {
|
|
1559
|
+
return null;
|
|
1560
|
+
}
|
|
1561
|
+
return {
|
|
1562
|
+
x,
|
|
1563
|
+
y,
|
|
1564
|
+
width: right - x,
|
|
1565
|
+
height: bottom - y
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
var init_coordinates = __esm({
|
|
1569
|
+
"src/utils/coordinates.ts"() {
|
|
1570
|
+
"use strict";
|
|
1571
|
+
}
|
|
1572
|
+
});
|
|
1573
|
+
|
|
1280
1574
|
// src/utils/index.ts
|
|
1281
1575
|
var init_utils = __esm({
|
|
1282
1576
|
"src/utils/index.ts"() {
|
|
@@ -1289,6 +1583,8 @@ var init_utils = __esm({
|
|
|
1289
1583
|
init_export_annotations();
|
|
1290
1584
|
init_student_storage();
|
|
1291
1585
|
init_agent_api();
|
|
1586
|
+
init_text_search();
|
|
1587
|
+
init_coordinates();
|
|
1292
1588
|
}
|
|
1293
1589
|
});
|
|
1294
1590
|
|
|
@@ -7926,6 +8222,8 @@ var init_DocumentContainer = __esm({
|
|
|
7926
8222
|
nextPage,
|
|
7927
8223
|
previousPage
|
|
7928
8224
|
} = usePDFViewer();
|
|
8225
|
+
const scrollToPageRequest = useViewerStore((s) => s.scrollToPageRequest);
|
|
8226
|
+
const { viewerStore } = usePDFViewerStores();
|
|
7929
8227
|
const [currentPageObj, setCurrentPageObj] = (0, import_react35.useState)(null);
|
|
7930
8228
|
const [isLoadingPage, setIsLoadingPage] = (0, import_react35.useState)(false);
|
|
7931
8229
|
const containerRef = (0, import_react35.useRef)(null);
|
|
@@ -7991,6 +8289,11 @@ var init_DocumentContainer = __esm({
|
|
|
7991
8289
|
const page = await document2.getPage(currentPage);
|
|
7992
8290
|
if (!cancelled && document2 === documentRef.current) {
|
|
7993
8291
|
setCurrentPageObj(page);
|
|
8292
|
+
if (scrollToPageRequest && scrollToPageRequest.page === currentPage) {
|
|
8293
|
+
requestAnimationFrame(() => {
|
|
8294
|
+
viewerStore.getState().completeScrollRequest(scrollToPageRequest.requestId);
|
|
8295
|
+
});
|
|
8296
|
+
}
|
|
7994
8297
|
}
|
|
7995
8298
|
} catch (error) {
|
|
7996
8299
|
if (!cancelled) {
|
|
@@ -8009,7 +8312,7 @@ var init_DocumentContainer = __esm({
|
|
|
8009
8312
|
return () => {
|
|
8010
8313
|
cancelled = true;
|
|
8011
8314
|
};
|
|
8012
|
-
}, [document2, currentPage]);
|
|
8315
|
+
}, [document2, currentPage, scrollToPageRequest, viewerStore]);
|
|
8013
8316
|
const getPageElement = (0, import_react35.useCallback)(() => {
|
|
8014
8317
|
return containerRef.current?.querySelector(`[data-page-number="${currentPage}"]`);
|
|
8015
8318
|
}, [currentPage]);
|
|
@@ -8151,6 +8454,8 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
8151
8454
|
nextPage,
|
|
8152
8455
|
previousPage
|
|
8153
8456
|
} = usePDFViewer();
|
|
8457
|
+
const scrollToPageRequest = useViewerStore((s) => s.scrollToPageRequest);
|
|
8458
|
+
const { viewerStore } = usePDFViewerStores();
|
|
8154
8459
|
const containerRef = (0, import_react36.useRef)(null);
|
|
8155
8460
|
const scrollContainerRef = (0, import_react36.useRef)(null);
|
|
8156
8461
|
const documentRef = (0, import_react36.useRef)(null);
|
|
@@ -8288,6 +8593,45 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
8288
8593
|
loadPages();
|
|
8289
8594
|
}, [document2, visiblePages, pageObjects]);
|
|
8290
8595
|
(0, import_react36.useEffect)(() => {
|
|
8596
|
+
if (!scrollToPageRequest || !scrollContainerRef.current || pageInfos.length === 0) return;
|
|
8597
|
+
const { page, requestId, behavior } = scrollToPageRequest;
|
|
8598
|
+
const pageInfo = pageInfos.find((p) => p.pageNumber === page);
|
|
8599
|
+
if (!pageInfo) {
|
|
8600
|
+
viewerStore.getState().completeScrollRequest(requestId);
|
|
8601
|
+
return;
|
|
8602
|
+
}
|
|
8603
|
+
const container = scrollContainerRef.current;
|
|
8604
|
+
const targetScroll = pageInfo.top - pageGap;
|
|
8605
|
+
const scrollTop = container.scrollTop;
|
|
8606
|
+
const viewportHeight = container.clientHeight;
|
|
8607
|
+
const isVisible = targetScroll >= scrollTop && pageInfo.top + pageInfo.height <= scrollTop + viewportHeight;
|
|
8608
|
+
if (isVisible) {
|
|
8609
|
+
viewerStore.getState().completeScrollRequest(requestId);
|
|
8610
|
+
return;
|
|
8611
|
+
}
|
|
8612
|
+
container.scrollTo({
|
|
8613
|
+
top: targetScroll,
|
|
8614
|
+
behavior
|
|
8615
|
+
});
|
|
8616
|
+
if (behavior === "instant") {
|
|
8617
|
+
requestAnimationFrame(() => {
|
|
8618
|
+
viewerStore.getState().completeScrollRequest(requestId);
|
|
8619
|
+
});
|
|
8620
|
+
} else {
|
|
8621
|
+
let scrollEndTimeout;
|
|
8622
|
+
const handleScrollEnd = () => {
|
|
8623
|
+
clearTimeout(scrollEndTimeout);
|
|
8624
|
+
scrollEndTimeout = setTimeout(() => {
|
|
8625
|
+
container.removeEventListener("scroll", handleScrollEnd);
|
|
8626
|
+
viewerStore.getState().completeScrollRequest(requestId);
|
|
8627
|
+
}, 100);
|
|
8628
|
+
};
|
|
8629
|
+
container.addEventListener("scroll", handleScrollEnd, { passive: true });
|
|
8630
|
+
handleScrollEnd();
|
|
8631
|
+
}
|
|
8632
|
+
}, [scrollToPageRequest, pageInfos, pageGap, viewerStore]);
|
|
8633
|
+
(0, import_react36.useEffect)(() => {
|
|
8634
|
+
if (scrollToPageRequest) return;
|
|
8291
8635
|
if (!scrollContainerRef.current || pageInfos.length === 0) return;
|
|
8292
8636
|
const pageInfo = pageInfos.find((p) => p.pageNumber === currentPage);
|
|
8293
8637
|
if (pageInfo) {
|
|
@@ -8302,7 +8646,7 @@ var init_VirtualizedDocumentContainer = __esm({
|
|
|
8302
8646
|
});
|
|
8303
8647
|
}
|
|
8304
8648
|
}
|
|
8305
|
-
}, [currentPage, pageInfos, pageGap]);
|
|
8649
|
+
}, [currentPage, pageInfos, pageGap, scrollToPageRequest]);
|
|
8306
8650
|
const handlePinchZoom = (0, import_react36.useCallback)(
|
|
8307
8651
|
(pinchScale) => {
|
|
8308
8652
|
const newScale = Math.max(0.25, Math.min(4, baseScaleRef.current * pinchScale));
|
|
@@ -8509,6 +8853,8 @@ var init_DualPageContainer = __esm({
|
|
|
8509
8853
|
setScale,
|
|
8510
8854
|
goToPage
|
|
8511
8855
|
} = usePDFViewer();
|
|
8856
|
+
const scrollToPageRequest = useViewerStore((s) => s.scrollToPageRequest);
|
|
8857
|
+
const { viewerStore } = usePDFViewerStores();
|
|
8512
8858
|
const containerRef = (0, import_react38.useRef)(null);
|
|
8513
8859
|
const documentRef = (0, import_react38.useRef)(null);
|
|
8514
8860
|
const baseScaleRef = (0, import_react38.useRef)(scale);
|
|
@@ -8594,6 +8940,14 @@ var init_DualPageContainer = __esm({
|
|
|
8594
8940
|
if (!cancelled) {
|
|
8595
8941
|
setLeftPage(left);
|
|
8596
8942
|
setRightPage(right);
|
|
8943
|
+
if (scrollToPageRequest) {
|
|
8944
|
+
const requestedPage = scrollToPageRequest.page;
|
|
8945
|
+
if (requestedPage === spread2.left || requestedPage === spread2.right) {
|
|
8946
|
+
requestAnimationFrame(() => {
|
|
8947
|
+
viewerStore.getState().completeScrollRequest(scrollToPageRequest.requestId);
|
|
8948
|
+
});
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
8597
8951
|
}
|
|
8598
8952
|
} catch (error) {
|
|
8599
8953
|
if (!cancelled) {
|
|
@@ -8609,7 +8963,7 @@ var init_DualPageContainer = __esm({
|
|
|
8609
8963
|
return () => {
|
|
8610
8964
|
cancelled = true;
|
|
8611
8965
|
};
|
|
8612
|
-
}, [document2, currentPage, getSpreadPages]);
|
|
8966
|
+
}, [document2, currentPage, getSpreadPages, scrollToPageRequest, viewerStore]);
|
|
8613
8967
|
const goToPreviousSpread = (0, import_react38.useCallback)(() => {
|
|
8614
8968
|
const spread2 = getSpreadPages(currentPage);
|
|
8615
8969
|
const leftmostPage = spread2.left || spread2.right || currentPage;
|
|
@@ -8806,10 +9160,14 @@ var init_FloatingZoomControls = __esm({
|
|
|
8806
9160
|
const scale = useViewerStore((s) => s.scale);
|
|
8807
9161
|
const document2 = useViewerStore((s) => s.document);
|
|
8808
9162
|
const handleZoomIn = (0, import_react39.useCallback)(() => {
|
|
8809
|
-
viewerStore.getState().
|
|
9163
|
+
const currentScale = viewerStore.getState().scale;
|
|
9164
|
+
const newScale = Math.min(4, currentScale + 0.05);
|
|
9165
|
+
viewerStore.getState().setScale(newScale);
|
|
8810
9166
|
}, [viewerStore]);
|
|
8811
9167
|
const handleZoomOut = (0, import_react39.useCallback)(() => {
|
|
8812
|
-
viewerStore.getState().
|
|
9168
|
+
const currentScale = viewerStore.getState().scale;
|
|
9169
|
+
const newScale = Math.max(0.1, currentScale - 0.05);
|
|
9170
|
+
viewerStore.getState().setScale(newScale);
|
|
8813
9171
|
}, [viewerStore]);
|
|
8814
9172
|
const handleFitToWidth = (0, import_react39.useCallback)(() => {
|
|
8815
9173
|
viewerStore.getState().setScale(1);
|
|
@@ -8975,6 +9333,7 @@ var init_PDFViewerClient = __esm({
|
|
|
8975
9333
|
PDFViewerInner = (0, import_react40.memo)(function PDFViewerInner2({
|
|
8976
9334
|
src,
|
|
8977
9335
|
initialPage = 1,
|
|
9336
|
+
page: controlledPage,
|
|
8978
9337
|
initialScale = "auto",
|
|
8979
9338
|
showToolbar = true,
|
|
8980
9339
|
showSidebar = true,
|
|
@@ -8984,9 +9343,17 @@ var init_PDFViewerClient = __esm({
|
|
|
8984
9343
|
onDocumentLoad,
|
|
8985
9344
|
onPageChange,
|
|
8986
9345
|
onScaleChange,
|
|
9346
|
+
onZoomChange,
|
|
8987
9347
|
onError,
|
|
9348
|
+
onPageRenderStart,
|
|
9349
|
+
onPageRenderComplete,
|
|
9350
|
+
onHighlightAdded,
|
|
9351
|
+
onHighlightRemoved,
|
|
9352
|
+
onAnnotationAdded,
|
|
8988
9353
|
workerSrc,
|
|
8989
9354
|
className,
|
|
9355
|
+
loadingComponent,
|
|
9356
|
+
errorComponent,
|
|
8990
9357
|
onReady
|
|
8991
9358
|
}) {
|
|
8992
9359
|
const { viewerStore, annotationStore, searchStore } = usePDFViewerStores();
|
|
@@ -8996,12 +9363,26 @@ var init_PDFViewerClient = __esm({
|
|
|
8996
9363
|
const onErrorRef = (0, import_react40.useRef)(onError);
|
|
8997
9364
|
const onPageChangeRef = (0, import_react40.useRef)(onPageChange);
|
|
8998
9365
|
const onScaleChangeRef = (0, import_react40.useRef)(onScaleChange);
|
|
9366
|
+
const onZoomChangeRef = (0, import_react40.useRef)(onZoomChange);
|
|
9367
|
+
const onPageRenderStartRef = (0, import_react40.useRef)(onPageRenderStart);
|
|
9368
|
+
const onPageRenderCompleteRef = (0, import_react40.useRef)(onPageRenderComplete);
|
|
9369
|
+
const onHighlightAddedRef = (0, import_react40.useRef)(onHighlightAdded);
|
|
9370
|
+
const onHighlightRemovedRef = (0, import_react40.useRef)(onHighlightRemoved);
|
|
9371
|
+
const onAnnotationAddedRef = (0, import_react40.useRef)(onAnnotationAdded);
|
|
8999
9372
|
const onReadyRef = (0, import_react40.useRef)(onReady);
|
|
9000
9373
|
onDocumentLoadRef.current = onDocumentLoad;
|
|
9001
9374
|
onErrorRef.current = onError;
|
|
9002
9375
|
onPageChangeRef.current = onPageChange;
|
|
9003
9376
|
onScaleChangeRef.current = onScaleChange;
|
|
9377
|
+
onZoomChangeRef.current = onZoomChange;
|
|
9378
|
+
onPageRenderStartRef.current = onPageRenderStart;
|
|
9379
|
+
onPageRenderCompleteRef.current = onPageRenderComplete;
|
|
9380
|
+
onHighlightAddedRef.current = onHighlightAdded;
|
|
9381
|
+
onHighlightRemovedRef.current = onHighlightRemoved;
|
|
9382
|
+
onAnnotationAddedRef.current = onAnnotationAdded;
|
|
9004
9383
|
onReadyRef.current = onReady;
|
|
9384
|
+
const isControlled = controlledPage !== void 0;
|
|
9385
|
+
const prevControlledPageRef = (0, import_react40.useRef)(controlledPage);
|
|
9005
9386
|
const srcIdRef = (0, import_react40.useRef)(null);
|
|
9006
9387
|
const currentPage = useViewerStore((s) => s.currentPage);
|
|
9007
9388
|
const scale = useViewerStore((s) => s.scale);
|
|
@@ -9142,8 +9523,9 @@ var init_PDFViewerClient = __esm({
|
|
|
9142
9523
|
}
|
|
9143
9524
|
},
|
|
9144
9525
|
// ==================== Navigation ====================
|
|
9145
|
-
goToPage: (page) => {
|
|
9146
|
-
|
|
9526
|
+
goToPage: async (page, options) => {
|
|
9527
|
+
const behavior = options?.behavior ?? "smooth";
|
|
9528
|
+
await viewerStore.getState().requestScrollToPage(page, behavior);
|
|
9147
9529
|
},
|
|
9148
9530
|
nextPage: () => {
|
|
9149
9531
|
viewerStore.getState().nextPage();
|
|
@@ -9203,6 +9585,246 @@ var init_PDFViewerClient = __esm({
|
|
|
9203
9585
|
clearSearch: () => {
|
|
9204
9586
|
searchStore.getState().clearSearch();
|
|
9205
9587
|
},
|
|
9588
|
+
// ==================== Combined Search & Highlight ====================
|
|
9589
|
+
searchAndHighlight: async (query, options) => {
|
|
9590
|
+
const doc = viewerStore.getState().document;
|
|
9591
|
+
if (!doc) {
|
|
9592
|
+
return { matchCount: 0, highlightIds: [], matches: [] };
|
|
9593
|
+
}
|
|
9594
|
+
const color = options?.color ?? "yellow";
|
|
9595
|
+
const caseSensitive = options?.caseSensitive ?? false;
|
|
9596
|
+
const wholeWord = options?.wholeWord ?? false;
|
|
9597
|
+
const scrollToFirst = options?.scrollToFirst ?? true;
|
|
9598
|
+
const clearPrevious = options?.clearPrevious ?? true;
|
|
9599
|
+
if (clearPrevious) {
|
|
9600
|
+
const existingHighlights = annotationStore.getState().highlights;
|
|
9601
|
+
for (const h of existingHighlights) {
|
|
9602
|
+
if (h.source === "search") {
|
|
9603
|
+
annotationStore.getState().removeHighlight(h.id);
|
|
9604
|
+
}
|
|
9605
|
+
}
|
|
9606
|
+
}
|
|
9607
|
+
let pagesToSearch;
|
|
9608
|
+
if (options?.pageRange) {
|
|
9609
|
+
if (Array.isArray(options.pageRange)) {
|
|
9610
|
+
pagesToSearch = options.pageRange;
|
|
9611
|
+
} else {
|
|
9612
|
+
const { start, end } = options.pageRange;
|
|
9613
|
+
pagesToSearch = Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
9614
|
+
}
|
|
9615
|
+
} else {
|
|
9616
|
+
pagesToSearch = Array.from({ length: doc.numPages }, (_, i) => i + 1);
|
|
9617
|
+
}
|
|
9618
|
+
const result = {
|
|
9619
|
+
matchCount: 0,
|
|
9620
|
+
highlightIds: [],
|
|
9621
|
+
matches: []
|
|
9622
|
+
};
|
|
9623
|
+
const searchText = caseSensitive ? query : query.toLowerCase();
|
|
9624
|
+
for (const pageNum of pagesToSearch) {
|
|
9625
|
+
if (pageNum < 1 || pageNum > doc.numPages) continue;
|
|
9626
|
+
try {
|
|
9627
|
+
const page = await doc.getPage(pageNum);
|
|
9628
|
+
const textContent = await page.getTextContent();
|
|
9629
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
9630
|
+
let fullText = "";
|
|
9631
|
+
const charPositions = [];
|
|
9632
|
+
for (const item of textContent.items) {
|
|
9633
|
+
if ("str" in item && item.str) {
|
|
9634
|
+
const tx = item.transform;
|
|
9635
|
+
const x = tx[4];
|
|
9636
|
+
const y = viewport.height - tx[5];
|
|
9637
|
+
const width = item.width ?? 0;
|
|
9638
|
+
const height = item.height ?? 12;
|
|
9639
|
+
const charWidth = item.str.length > 0 ? width / item.str.length : width;
|
|
9640
|
+
for (let i = 0; i < item.str.length; i++) {
|
|
9641
|
+
charPositions.push({
|
|
9642
|
+
char: item.str[i],
|
|
9643
|
+
rect: {
|
|
9644
|
+
x: x + i * charWidth,
|
|
9645
|
+
y: y - height,
|
|
9646
|
+
width: charWidth,
|
|
9647
|
+
height
|
|
9648
|
+
}
|
|
9649
|
+
});
|
|
9650
|
+
}
|
|
9651
|
+
fullText += item.str;
|
|
9652
|
+
}
|
|
9653
|
+
}
|
|
9654
|
+
const textToSearch = caseSensitive ? fullText : fullText.toLowerCase();
|
|
9655
|
+
let startIndex = 0;
|
|
9656
|
+
while (true) {
|
|
9657
|
+
let matchIndex = textToSearch.indexOf(searchText, startIndex);
|
|
9658
|
+
if (matchIndex === -1) break;
|
|
9659
|
+
if (wholeWord) {
|
|
9660
|
+
const beforeChar = matchIndex > 0 ? textToSearch[matchIndex - 1] : " ";
|
|
9661
|
+
const afterChar = matchIndex + query.length < textToSearch.length ? textToSearch[matchIndex + query.length] : " ";
|
|
9662
|
+
if (/\w/.test(beforeChar) || /\w/.test(afterChar)) {
|
|
9663
|
+
startIndex = matchIndex + 1;
|
|
9664
|
+
continue;
|
|
9665
|
+
}
|
|
9666
|
+
}
|
|
9667
|
+
const matchRects = [];
|
|
9668
|
+
for (let i = matchIndex; i < matchIndex + query.length && i < charPositions.length; i++) {
|
|
9669
|
+
matchRects.push(charPositions[i].rect);
|
|
9670
|
+
}
|
|
9671
|
+
const mergedRects = mergeRects2(matchRects);
|
|
9672
|
+
const highlight = annotationStore.getState().addHighlight({
|
|
9673
|
+
pageNumber: pageNum,
|
|
9674
|
+
rects: mergedRects,
|
|
9675
|
+
color,
|
|
9676
|
+
text: fullText.substring(matchIndex, matchIndex + query.length),
|
|
9677
|
+
source: "search"
|
|
9678
|
+
});
|
|
9679
|
+
result.matchCount++;
|
|
9680
|
+
result.highlightIds.push(highlight.id);
|
|
9681
|
+
result.matches.push({
|
|
9682
|
+
pageNumber: pageNum,
|
|
9683
|
+
text: fullText.substring(matchIndex, matchIndex + query.length),
|
|
9684
|
+
highlightId: highlight.id,
|
|
9685
|
+
rects: mergedRects
|
|
9686
|
+
});
|
|
9687
|
+
startIndex = matchIndex + 1;
|
|
9688
|
+
}
|
|
9689
|
+
} catch {
|
|
9690
|
+
}
|
|
9691
|
+
}
|
|
9692
|
+
if (scrollToFirst && result.matches.length > 0) {
|
|
9693
|
+
const firstMatch = result.matches[0];
|
|
9694
|
+
await viewerStore.getState().requestScrollToPage(firstMatch.pageNumber, "smooth");
|
|
9695
|
+
}
|
|
9696
|
+
return result;
|
|
9697
|
+
},
|
|
9698
|
+
// ==================== Agent Tools ====================
|
|
9699
|
+
agentTools: {
|
|
9700
|
+
navigateToPage: async (page) => {
|
|
9701
|
+
try {
|
|
9702
|
+
const { currentPage: currentPage2, numPages } = viewerStore.getState();
|
|
9703
|
+
if (numPages === 0) {
|
|
9704
|
+
return {
|
|
9705
|
+
success: false,
|
|
9706
|
+
error: { code: "NO_DOCUMENT", message: "No document is loaded" }
|
|
9707
|
+
};
|
|
9708
|
+
}
|
|
9709
|
+
if (page < 1 || page > numPages) {
|
|
9710
|
+
return {
|
|
9711
|
+
success: false,
|
|
9712
|
+
error: { code: "INVALID_PAGE", message: `Page ${page} is out of range (1-${numPages})` }
|
|
9713
|
+
};
|
|
9714
|
+
}
|
|
9715
|
+
const previousPage = currentPage2;
|
|
9716
|
+
await viewerStore.getState().requestScrollToPage(page, "smooth");
|
|
9717
|
+
return {
|
|
9718
|
+
success: true,
|
|
9719
|
+
data: { previousPage, currentPage: page }
|
|
9720
|
+
};
|
|
9721
|
+
} catch (err) {
|
|
9722
|
+
return {
|
|
9723
|
+
success: false,
|
|
9724
|
+
error: { code: "NAVIGATION_FAILED", message: err instanceof Error ? err.message : "Unknown error" }
|
|
9725
|
+
};
|
|
9726
|
+
}
|
|
9727
|
+
},
|
|
9728
|
+
highlightText: async (text, options) => {
|
|
9729
|
+
try {
|
|
9730
|
+
const highlightIds = await handle.highlightText(text, options);
|
|
9731
|
+
return {
|
|
9732
|
+
success: true,
|
|
9733
|
+
data: { matchCount: highlightIds.length, highlightIds }
|
|
9734
|
+
};
|
|
9735
|
+
} catch (err) {
|
|
9736
|
+
return {
|
|
9737
|
+
success: false,
|
|
9738
|
+
error: { code: "HIGHLIGHT_FAILED", message: err instanceof Error ? err.message : "Unknown error" }
|
|
9739
|
+
};
|
|
9740
|
+
}
|
|
9741
|
+
},
|
|
9742
|
+
getPageContent: async (page) => {
|
|
9743
|
+
try {
|
|
9744
|
+
const doc = viewerStore.getState().document;
|
|
9745
|
+
if (!doc) {
|
|
9746
|
+
return {
|
|
9747
|
+
success: false,
|
|
9748
|
+
error: { code: "NO_DOCUMENT", message: "No document is loaded" }
|
|
9749
|
+
};
|
|
9750
|
+
}
|
|
9751
|
+
if (page < 1 || page > doc.numPages) {
|
|
9752
|
+
return {
|
|
9753
|
+
success: false,
|
|
9754
|
+
error: { code: "INVALID_PAGE", message: `Page ${page} is out of range (1-${doc.numPages})` }
|
|
9755
|
+
};
|
|
9756
|
+
}
|
|
9757
|
+
const pageObj = await doc.getPage(page);
|
|
9758
|
+
const textContent = await pageObj.getTextContent();
|
|
9759
|
+
const text = textContent.items.filter((item) => "str" in item).map((item) => item.str).join("");
|
|
9760
|
+
return {
|
|
9761
|
+
success: true,
|
|
9762
|
+
data: { text }
|
|
9763
|
+
};
|
|
9764
|
+
} catch (err) {
|
|
9765
|
+
return {
|
|
9766
|
+
success: false,
|
|
9767
|
+
error: { code: "CONTENT_FETCH_FAILED", message: err instanceof Error ? err.message : "Unknown error" }
|
|
9768
|
+
};
|
|
9769
|
+
}
|
|
9770
|
+
},
|
|
9771
|
+
clearAllVisuals: async () => {
|
|
9772
|
+
try {
|
|
9773
|
+
const highlights = annotationStore.getState().highlights;
|
|
9774
|
+
for (const h of highlights) {
|
|
9775
|
+
annotationStore.getState().removeHighlight(h.id);
|
|
9776
|
+
}
|
|
9777
|
+
const annotations = annotationStore.getState().annotations;
|
|
9778
|
+
for (const a of annotations) {
|
|
9779
|
+
annotationStore.getState().removeAnnotation(a.id);
|
|
9780
|
+
}
|
|
9781
|
+
return { success: true };
|
|
9782
|
+
} catch (err) {
|
|
9783
|
+
return {
|
|
9784
|
+
success: false,
|
|
9785
|
+
error: { code: "CLEAR_FAILED", message: err instanceof Error ? err.message : "Unknown error" }
|
|
9786
|
+
};
|
|
9787
|
+
}
|
|
9788
|
+
}
|
|
9789
|
+
},
|
|
9790
|
+
// ==================== Coordinate Helpers ====================
|
|
9791
|
+
coordinates: {
|
|
9792
|
+
getPageDimensions: (page) => {
|
|
9793
|
+
const doc = viewerStore.getState().document;
|
|
9794
|
+
if (!doc || page < 1 || page > doc.numPages) {
|
|
9795
|
+
return null;
|
|
9796
|
+
}
|
|
9797
|
+
try {
|
|
9798
|
+
return {
|
|
9799
|
+
width: 612,
|
|
9800
|
+
// Default US Letter width
|
|
9801
|
+
height: 792,
|
|
9802
|
+
// Default US Letter height
|
|
9803
|
+
rotation: viewerStore.getState().rotation
|
|
9804
|
+
};
|
|
9805
|
+
} catch {
|
|
9806
|
+
return null;
|
|
9807
|
+
}
|
|
9808
|
+
},
|
|
9809
|
+
percentToPixels: (xPercent, yPercent, page) => {
|
|
9810
|
+
const dimensions = handle.coordinates.getPageDimensions(page);
|
|
9811
|
+
if (!dimensions) return null;
|
|
9812
|
+
const scale2 = viewerStore.getState().scale;
|
|
9813
|
+
return {
|
|
9814
|
+
x: xPercent / 100 * dimensions.width * scale2,
|
|
9815
|
+
y: yPercent / 100 * dimensions.height * scale2
|
|
9816
|
+
};
|
|
9817
|
+
},
|
|
9818
|
+
pixelsToPercent: (x, y, page) => {
|
|
9819
|
+
const dimensions = handle.coordinates.getPageDimensions(page);
|
|
9820
|
+
if (!dimensions) return null;
|
|
9821
|
+
const scale2 = viewerStore.getState().scale;
|
|
9822
|
+
return {
|
|
9823
|
+
x: x / (dimensions.width * scale2) * 100,
|
|
9824
|
+
y: y / (dimensions.height * scale2) * 100
|
|
9825
|
+
};
|
|
9826
|
+
}
|
|
9827
|
+
},
|
|
9206
9828
|
// ==================== Document ====================
|
|
9207
9829
|
getDocument: () => {
|
|
9208
9830
|
return viewerStore.getState().document;
|
|
@@ -9289,10 +9911,36 @@ var init_PDFViewerClient = __esm({
|
|
|
9289
9911
|
if (prevScaleRef.current !== scale) {
|
|
9290
9912
|
prevScaleRef.current = scale;
|
|
9291
9913
|
onScaleChangeRef.current?.(scale);
|
|
9914
|
+
onZoomChangeRef.current?.(scale);
|
|
9292
9915
|
}
|
|
9293
9916
|
}, [scale]);
|
|
9917
|
+
(0, import_react40.useEffect)(() => {
|
|
9918
|
+
if (!isControlled || controlledPage === void 0) return;
|
|
9919
|
+
if (prevControlledPageRef.current === controlledPage) return;
|
|
9920
|
+
prevControlledPageRef.current = controlledPage;
|
|
9921
|
+
const { numPages, currentPage: currentPage2 } = viewerStore.getState();
|
|
9922
|
+
if (numPages > 0 && controlledPage !== currentPage2) {
|
|
9923
|
+
viewerStore.getState().requestScrollToPage(controlledPage, "smooth");
|
|
9924
|
+
}
|
|
9925
|
+
}, [controlledPage, isControlled, viewerStore]);
|
|
9294
9926
|
const themeClass = theme === "dark" ? "dark" : "";
|
|
9295
9927
|
if (error) {
|
|
9928
|
+
if (errorComponent) {
|
|
9929
|
+
const errorContent = typeof errorComponent === "function" ? errorComponent(error, handleRetry) : errorComponent;
|
|
9930
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
9931
|
+
"div",
|
|
9932
|
+
{
|
|
9933
|
+
className: cn(
|
|
9934
|
+
"pdf-viewer pdf-viewer-error",
|
|
9935
|
+
"flex flex-col h-full",
|
|
9936
|
+
"bg-white dark:bg-gray-900",
|
|
9937
|
+
themeClass,
|
|
9938
|
+
className
|
|
9939
|
+
),
|
|
9940
|
+
children: errorContent
|
|
9941
|
+
}
|
|
9942
|
+
);
|
|
9943
|
+
}
|
|
9296
9944
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
9297
9945
|
"div",
|
|
9298
9946
|
{
|
|
@@ -9348,7 +9996,7 @@ var init_PDFViewerClient = __esm({
|
|
|
9348
9996
|
renderContainer()
|
|
9349
9997
|
] }),
|
|
9350
9998
|
showFloatingZoom && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(FloatingZoomControls, { position: "bottom-right" }),
|
|
9351
|
-
isLoading && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col items-center", children: [
|
|
9999
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-white/80 dark:bg-gray-900/80", children: loadingComponent ?? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex flex-col items-center", children: [
|
|
9352
10000
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin" }),
|
|
9353
10001
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mt-2 text-sm text-gray-500", children: "Loading PDF..." })
|
|
9354
10002
|
] }) })
|
|
@@ -9461,6 +10109,7 @@ __export(index_exports, {
|
|
|
9461
10109
|
OutlinePanel: () => OutlinePanel,
|
|
9462
10110
|
PDFErrorBoundary: () => PDFErrorBoundary,
|
|
9463
10111
|
PDFPage: () => PDFPage,
|
|
10112
|
+
PDFThumbnailNav: () => PDFThumbnailNav,
|
|
9464
10113
|
PDFViewer: () => PDFViewer,
|
|
9465
10114
|
PDFViewerClient: () => PDFViewerClient,
|
|
9466
10115
|
PDFViewerContext: () => PDFViewerContext,
|
|
@@ -9479,9 +10128,11 @@ __export(index_exports, {
|
|
|
9479
10128
|
ThumbnailPanel: () => ThumbnailPanel,
|
|
9480
10129
|
Toolbar: () => Toolbar,
|
|
9481
10130
|
VirtualizedDocumentContainer: () => VirtualizedDocumentContainer,
|
|
10131
|
+
applyRotation: () => applyRotation,
|
|
9482
10132
|
clearHighlights: () => clearHighlights,
|
|
9483
10133
|
clearStudentData: () => clearStudentData,
|
|
9484
10134
|
cn: () => cn,
|
|
10135
|
+
countTextOnPage: () => countTextOnPage,
|
|
9485
10136
|
createAgentAPI: () => createAgentAPI,
|
|
9486
10137
|
createAgentStore: () => createAgentStore,
|
|
9487
10138
|
createAnnotationStore: () => createAnnotationStore,
|
|
@@ -9490,6 +10141,7 @@ __export(index_exports, {
|
|
|
9490
10141
|
createSearchStore: () => createSearchStore,
|
|
9491
10142
|
createStudentStore: () => createStudentStore,
|
|
9492
10143
|
createViewerStore: () => createViewerStore,
|
|
10144
|
+
doRectsIntersect: () => doRectsIntersect,
|
|
9493
10145
|
downloadAnnotationsAsJSON: () => downloadAnnotationsAsJSON,
|
|
9494
10146
|
downloadAnnotationsAsMarkdown: () => downloadAnnotationsAsMarkdown,
|
|
9495
10147
|
downloadFile: () => downloadFile,
|
|
@@ -9497,25 +10149,39 @@ __export(index_exports, {
|
|
|
9497
10149
|
exportAnnotationsAsMarkdown: () => exportAnnotationsAsMarkdown,
|
|
9498
10150
|
exportHighlightsAsJSON: () => exportHighlightsAsJSON,
|
|
9499
10151
|
exportHighlightsAsMarkdown: () => exportHighlightsAsMarkdown,
|
|
10152
|
+
extractPageText: () => extractPageText,
|
|
10153
|
+
findTextInDocument: () => findTextInDocument,
|
|
10154
|
+
findTextOnPage: () => findTextOnPage,
|
|
9500
10155
|
generateDocumentId: () => generateDocumentId,
|
|
9501
10156
|
getAllDocumentIds: () => getAllDocumentIds,
|
|
9502
10157
|
getAllStudentDataDocumentIds: () => getAllStudentDataDocumentIds,
|
|
9503
10158
|
getMetadata: () => getMetadata,
|
|
9504
10159
|
getOutline: () => getOutline,
|
|
9505
10160
|
getPage: () => getPage,
|
|
10161
|
+
getPageText: () => getPageText,
|
|
9506
10162
|
getPageTextContent: () => getPageTextContent,
|
|
9507
10163
|
getPluginManager: () => getPluginManager,
|
|
10164
|
+
getRectIntersection: () => getRectIntersection,
|
|
10165
|
+
getRotatedDimensions: () => getRotatedDimensions,
|
|
9508
10166
|
getStorageStats: () => getStorageStats,
|
|
9509
10167
|
importHighlightsFromJSON: () => importHighlightsFromJSON,
|
|
9510
10168
|
initializePDFJS: () => initializePDFJS,
|
|
9511
10169
|
isPDFJSInitialized: () => isPDFJSInitialized,
|
|
10170
|
+
isPointInRect: () => isPointInRect,
|
|
9512
10171
|
loadDocument: () => loadDocument,
|
|
9513
10172
|
loadHighlights: () => loadHighlights,
|
|
9514
10173
|
loadStudentData: () => loadStudentData,
|
|
10174
|
+
mergeAdjacentRects: () => mergeAdjacentRects,
|
|
10175
|
+
pdfToPercent: () => pdfToPercent,
|
|
10176
|
+
pdfToViewport: () => pdfToViewport,
|
|
9515
10177
|
pdfjsLib: () => pdfjsLib,
|
|
10178
|
+
percentToPDF: () => percentToPDF,
|
|
10179
|
+
percentToViewport: () => percentToViewport,
|
|
9516
10180
|
quickViewer: () => quickViewer,
|
|
10181
|
+
removeRotation: () => removeRotation,
|
|
9517
10182
|
saveHighlights: () => saveHighlights,
|
|
9518
10183
|
saveStudentData: () => saveStudentData,
|
|
10184
|
+
scaleRect: () => scaleRect,
|
|
9519
10185
|
useAgentContext: () => useAgentContext,
|
|
9520
10186
|
useAgentStore: () => useAgentStore,
|
|
9521
10187
|
useAnnotationStore: () => useAnnotationStore,
|
|
@@ -9537,6 +10203,8 @@ __export(index_exports, {
|
|
|
9537
10203
|
useTouchGestures: () => useTouchGestures,
|
|
9538
10204
|
useViewerStore: () => useViewerStore,
|
|
9539
10205
|
useZoom: () => useZoom,
|
|
10206
|
+
viewportToPDF: () => viewportToPDF,
|
|
10207
|
+
viewportToPercent: () => viewportToPercent,
|
|
9540
10208
|
withErrorBoundary: () => withErrorBoundary
|
|
9541
10209
|
});
|
|
9542
10210
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -10826,11 +11494,248 @@ var Minimap = (0, import_react49.memo)(function Minimap2({
|
|
|
10826
11494
|
// src/components/index.ts
|
|
10827
11495
|
init_FloatingZoomControls2();
|
|
10828
11496
|
|
|
10829
|
-
// src/components/
|
|
11497
|
+
// src/components/PDFThumbnailNav/PDFThumbnailNav.tsx
|
|
10830
11498
|
var import_react50 = require("react");
|
|
11499
|
+
init_hooks();
|
|
10831
11500
|
init_utils();
|
|
10832
11501
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
10833
|
-
var
|
|
11502
|
+
var DEFAULT_WIDTH = 612;
|
|
11503
|
+
var DEFAULT_HEIGHT = 792;
|
|
11504
|
+
var PDFThumbnailNav = (0, import_react50.memo)(function PDFThumbnailNav2({
|
|
11505
|
+
thumbnailScale = 0.15,
|
|
11506
|
+
orientation = "vertical",
|
|
11507
|
+
maxVisible = 10,
|
|
11508
|
+
className,
|
|
11509
|
+
onThumbnailClick,
|
|
11510
|
+
gap = 8,
|
|
11511
|
+
showPageNumbers = true
|
|
11512
|
+
}) {
|
|
11513
|
+
const { document: document2, numPages, currentPage } = usePDFViewer();
|
|
11514
|
+
const { viewerStore } = usePDFViewerStores();
|
|
11515
|
+
const containerRef = (0, import_react50.useRef)(null);
|
|
11516
|
+
const [thumbnails, setThumbnails] = (0, import_react50.useState)(/* @__PURE__ */ new Map());
|
|
11517
|
+
const [visibleRange, setVisibleRange] = (0, import_react50.useState)({ start: 1, end: maxVisible });
|
|
11518
|
+
const renderQueueRef = (0, import_react50.useRef)(/* @__PURE__ */ new Set());
|
|
11519
|
+
const pageCache = (0, import_react50.useRef)(/* @__PURE__ */ new Map());
|
|
11520
|
+
const thumbnailWidth = Math.floor(DEFAULT_WIDTH * thumbnailScale);
|
|
11521
|
+
const thumbnailHeight = Math.floor(DEFAULT_HEIGHT * thumbnailScale);
|
|
11522
|
+
const updateVisibleRange = (0, import_react50.useCallback)(() => {
|
|
11523
|
+
if (!containerRef.current || numPages === 0) return;
|
|
11524
|
+
const container = containerRef.current;
|
|
11525
|
+
const isHorizontal2 = orientation === "horizontal";
|
|
11526
|
+
const scrollPosition = isHorizontal2 ? container.scrollLeft : container.scrollTop;
|
|
11527
|
+
const viewportSize = isHorizontal2 ? container.clientWidth : container.clientHeight;
|
|
11528
|
+
const itemSize = (isHorizontal2 ? thumbnailWidth : thumbnailHeight) + gap;
|
|
11529
|
+
const firstVisible = Math.max(1, Math.floor(scrollPosition / itemSize) + 1);
|
|
11530
|
+
const visibleCount = Math.ceil(viewportSize / itemSize) + 2;
|
|
11531
|
+
const lastVisible = Math.min(numPages, firstVisible + visibleCount);
|
|
11532
|
+
setVisibleRange({ start: firstVisible, end: lastVisible });
|
|
11533
|
+
}, [numPages, orientation, thumbnailWidth, thumbnailHeight, gap]);
|
|
11534
|
+
(0, import_react50.useEffect)(() => {
|
|
11535
|
+
const container = containerRef.current;
|
|
11536
|
+
if (!container) return;
|
|
11537
|
+
const handleScroll = () => {
|
|
11538
|
+
requestAnimationFrame(updateVisibleRange);
|
|
11539
|
+
};
|
|
11540
|
+
container.addEventListener("scroll", handleScroll, { passive: true });
|
|
11541
|
+
updateVisibleRange();
|
|
11542
|
+
return () => container.removeEventListener("scroll", handleScroll);
|
|
11543
|
+
}, [updateVisibleRange]);
|
|
11544
|
+
(0, import_react50.useEffect)(() => {
|
|
11545
|
+
if (!document2) {
|
|
11546
|
+
setThumbnails(/* @__PURE__ */ new Map());
|
|
11547
|
+
pageCache.current.clear();
|
|
11548
|
+
return;
|
|
11549
|
+
}
|
|
11550
|
+
const renderThumbnails = async () => {
|
|
11551
|
+
const newThumbnails = new Map(thumbnails);
|
|
11552
|
+
const pagesToRender = [];
|
|
11553
|
+
for (let i = visibleRange.start; i <= visibleRange.end; i++) {
|
|
11554
|
+
if (!newThumbnails.has(i) && !renderQueueRef.current.has(i)) {
|
|
11555
|
+
pagesToRender.push(i);
|
|
11556
|
+
renderQueueRef.current.add(i);
|
|
11557
|
+
}
|
|
11558
|
+
}
|
|
11559
|
+
for (const pageNum of pagesToRender) {
|
|
11560
|
+
try {
|
|
11561
|
+
let page = pageCache.current.get(pageNum);
|
|
11562
|
+
if (!page) {
|
|
11563
|
+
page = await document2.getPage(pageNum);
|
|
11564
|
+
pageCache.current.set(pageNum, page);
|
|
11565
|
+
}
|
|
11566
|
+
const viewport = page.getViewport({ scale: thumbnailScale });
|
|
11567
|
+
const canvas = window.document.createElement("canvas");
|
|
11568
|
+
canvas.width = Math.floor(viewport.width);
|
|
11569
|
+
canvas.height = Math.floor(viewport.height);
|
|
11570
|
+
const ctx = canvas.getContext("2d");
|
|
11571
|
+
if (ctx) {
|
|
11572
|
+
await page.render({
|
|
11573
|
+
canvasContext: ctx,
|
|
11574
|
+
viewport
|
|
11575
|
+
}).promise;
|
|
11576
|
+
newThumbnails.set(pageNum, {
|
|
11577
|
+
pageNumber: pageNum,
|
|
11578
|
+
canvas,
|
|
11579
|
+
width: canvas.width,
|
|
11580
|
+
height: canvas.height
|
|
11581
|
+
});
|
|
11582
|
+
}
|
|
11583
|
+
} catch (error) {
|
|
11584
|
+
console.error(`Failed to render thumbnail for page ${pageNum}:`, error);
|
|
11585
|
+
} finally {
|
|
11586
|
+
renderQueueRef.current.delete(pageNum);
|
|
11587
|
+
}
|
|
11588
|
+
}
|
|
11589
|
+
if (pagesToRender.length > 0) {
|
|
11590
|
+
setThumbnails(newThumbnails);
|
|
11591
|
+
}
|
|
11592
|
+
};
|
|
11593
|
+
renderThumbnails();
|
|
11594
|
+
}, [document2, visibleRange, thumbnailScale, thumbnails]);
|
|
11595
|
+
(0, import_react50.useEffect)(() => {
|
|
11596
|
+
if (!containerRef.current || numPages === 0) return;
|
|
11597
|
+
const container = containerRef.current;
|
|
11598
|
+
const isHorizontal2 = orientation === "horizontal";
|
|
11599
|
+
const itemSize = (isHorizontal2 ? thumbnailWidth : thumbnailHeight) + gap;
|
|
11600
|
+
const targetPosition = (currentPage - 1) * itemSize;
|
|
11601
|
+
const scrollPosition = isHorizontal2 ? container.scrollLeft : container.scrollTop;
|
|
11602
|
+
const viewportSize = isHorizontal2 ? container.clientWidth : container.clientHeight;
|
|
11603
|
+
if (targetPosition < scrollPosition || targetPosition + itemSize > scrollPosition + viewportSize) {
|
|
11604
|
+
const targetScroll = targetPosition - (viewportSize - itemSize) / 2;
|
|
11605
|
+
container.scrollTo({
|
|
11606
|
+
[isHorizontal2 ? "left" : "top"]: Math.max(0, targetScroll),
|
|
11607
|
+
behavior: "smooth"
|
|
11608
|
+
});
|
|
11609
|
+
}
|
|
11610
|
+
}, [currentPage, numPages, orientation, thumbnailWidth, thumbnailHeight, gap]);
|
|
11611
|
+
const handleThumbnailClick = (0, import_react50.useCallback)((pageNum) => {
|
|
11612
|
+
onThumbnailClick?.(pageNum);
|
|
11613
|
+
viewerStore.getState().requestScrollToPage(pageNum, "smooth");
|
|
11614
|
+
}, [onThumbnailClick, viewerStore]);
|
|
11615
|
+
if (!document2 || numPages === 0) {
|
|
11616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11617
|
+
"div",
|
|
11618
|
+
{
|
|
11619
|
+
className: cn(
|
|
11620
|
+
"pdf-thumbnail-nav",
|
|
11621
|
+
"flex items-center justify-center",
|
|
11622
|
+
"bg-gray-100 dark:bg-gray-800",
|
|
11623
|
+
"text-gray-500 dark:text-gray-400",
|
|
11624
|
+
"text-sm",
|
|
11625
|
+
className
|
|
11626
|
+
),
|
|
11627
|
+
style: {
|
|
11628
|
+
width: orientation === "vertical" ? thumbnailWidth + 24 : "100%",
|
|
11629
|
+
height: orientation === "horizontal" ? thumbnailHeight + 40 : "100%"
|
|
11630
|
+
},
|
|
11631
|
+
children: "No document"
|
|
11632
|
+
}
|
|
11633
|
+
);
|
|
11634
|
+
}
|
|
11635
|
+
const isHorizontal = orientation === "horizontal";
|
|
11636
|
+
const totalSize = numPages * ((isHorizontal ? thumbnailWidth : thumbnailHeight) + gap) - gap;
|
|
11637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11638
|
+
"div",
|
|
11639
|
+
{
|
|
11640
|
+
ref: containerRef,
|
|
11641
|
+
className: cn(
|
|
11642
|
+
"pdf-thumbnail-nav",
|
|
11643
|
+
"overflow-auto",
|
|
11644
|
+
"bg-gray-100 dark:bg-gray-800",
|
|
11645
|
+
isHorizontal ? "flex-row" : "flex-col",
|
|
11646
|
+
className
|
|
11647
|
+
),
|
|
11648
|
+
style: {
|
|
11649
|
+
...isHorizontal ? { overflowX: "auto", overflowY: "hidden" } : { overflowX: "hidden", overflowY: "auto" }
|
|
11650
|
+
},
|
|
11651
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11652
|
+
"div",
|
|
11653
|
+
{
|
|
11654
|
+
className: cn(
|
|
11655
|
+
"relative",
|
|
11656
|
+
isHorizontal ? "flex flex-row items-center" : "flex flex-col items-center"
|
|
11657
|
+
),
|
|
11658
|
+
style: {
|
|
11659
|
+
[isHorizontal ? "width" : "height"]: totalSize,
|
|
11660
|
+
[isHorizontal ? "minWidth" : "minHeight"]: totalSize,
|
|
11661
|
+
padding: gap / 2,
|
|
11662
|
+
gap
|
|
11663
|
+
},
|
|
11664
|
+
children: Array.from({ length: numPages }, (_, i) => i + 1).map((pageNum) => {
|
|
11665
|
+
const thumbnail = thumbnails.get(pageNum);
|
|
11666
|
+
const isActive = pageNum === currentPage;
|
|
11667
|
+
const isVisible = pageNum >= visibleRange.start && pageNum <= visibleRange.end;
|
|
11668
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
11669
|
+
"div",
|
|
11670
|
+
{
|
|
11671
|
+
className: cn(
|
|
11672
|
+
"pdf-thumbnail",
|
|
11673
|
+
"flex-shrink-0 cursor-pointer transition-all duration-200",
|
|
11674
|
+
"border-2 rounded shadow-sm hover:shadow-md",
|
|
11675
|
+
isActive ? "border-blue-500 ring-2 ring-blue-200 dark:ring-blue-800" : "border-gray-300 dark:border-gray-600 hover:border-blue-400"
|
|
11676
|
+
),
|
|
11677
|
+
style: {
|
|
11678
|
+
width: thumbnailWidth,
|
|
11679
|
+
height: thumbnailHeight + (showPageNumbers ? 24 : 0)
|
|
11680
|
+
},
|
|
11681
|
+
onClick: () => handleThumbnailClick(pageNum),
|
|
11682
|
+
role: "button",
|
|
11683
|
+
tabIndex: 0,
|
|
11684
|
+
"aria-label": `Go to page ${pageNum}`,
|
|
11685
|
+
"aria-current": isActive ? "page" : void 0,
|
|
11686
|
+
onKeyDown: (e) => {
|
|
11687
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
11688
|
+
e.preventDefault();
|
|
11689
|
+
handleThumbnailClick(pageNum);
|
|
11690
|
+
}
|
|
11691
|
+
},
|
|
11692
|
+
children: [
|
|
11693
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11694
|
+
"div",
|
|
11695
|
+
{
|
|
11696
|
+
className: "relative bg-white dark:bg-gray-700",
|
|
11697
|
+
style: {
|
|
11698
|
+
width: thumbnailWidth,
|
|
11699
|
+
height: thumbnailHeight
|
|
11700
|
+
},
|
|
11701
|
+
children: isVisible && thumbnail?.canvas ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11702
|
+
"img",
|
|
11703
|
+
{
|
|
11704
|
+
src: thumbnail.canvas.toDataURL(),
|
|
11705
|
+
alt: `Page ${pageNum}`,
|
|
11706
|
+
className: "w-full h-full object-contain",
|
|
11707
|
+
loading: "lazy"
|
|
11708
|
+
}
|
|
11709
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "absolute inset-0 flex items-center justify-center text-gray-400 dark:text-gray-500 text-xs", children: pageNum })
|
|
11710
|
+
}
|
|
11711
|
+
),
|
|
11712
|
+
showPageNumbers && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
11713
|
+
"div",
|
|
11714
|
+
{
|
|
11715
|
+
className: cn(
|
|
11716
|
+
"text-center text-xs py-1",
|
|
11717
|
+
"bg-gray-50 dark:bg-gray-700",
|
|
11718
|
+
isActive ? "text-blue-600 dark:text-blue-400 font-medium" : "text-gray-600 dark:text-gray-400"
|
|
11719
|
+
),
|
|
11720
|
+
children: pageNum
|
|
11721
|
+
}
|
|
11722
|
+
)
|
|
11723
|
+
]
|
|
11724
|
+
},
|
|
11725
|
+
pageNum
|
|
11726
|
+
);
|
|
11727
|
+
})
|
|
11728
|
+
}
|
|
11729
|
+
)
|
|
11730
|
+
}
|
|
11731
|
+
);
|
|
11732
|
+
});
|
|
11733
|
+
|
|
11734
|
+
// src/components/ErrorBoundary/PDFErrorBoundary.tsx
|
|
11735
|
+
var import_react51 = require("react");
|
|
11736
|
+
init_utils();
|
|
11737
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
11738
|
+
var PDFErrorBoundary = class extends import_react51.Component {
|
|
10834
11739
|
constructor(props) {
|
|
10835
11740
|
super(props);
|
|
10836
11741
|
this.handleReset = () => {
|
|
@@ -10857,7 +11762,7 @@ var PDFErrorBoundary = class extends import_react50.Component {
|
|
|
10857
11762
|
return fallback;
|
|
10858
11763
|
}
|
|
10859
11764
|
if (showDefaultUI) {
|
|
10860
|
-
return /* @__PURE__ */ (0,
|
|
11765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10861
11766
|
DefaultErrorUI,
|
|
10862
11767
|
{
|
|
10863
11768
|
error,
|
|
@@ -10876,7 +11781,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10876
11781
|
const isNetworkError = error.message.includes("fetch") || error.message.includes("network") || error.message.includes("Failed to load");
|
|
10877
11782
|
let title = "Something went wrong";
|
|
10878
11783
|
let description = error.message;
|
|
10879
|
-
let icon = /* @__PURE__ */ (0,
|
|
11784
|
+
let icon = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("svg", { className: "w-12 h-12 text-red-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10880
11785
|
"path",
|
|
10881
11786
|
{
|
|
10882
11787
|
strokeLinecap: "round",
|
|
@@ -10888,7 +11793,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10888
11793
|
if (isPDFError) {
|
|
10889
11794
|
title = "Unable to load PDF";
|
|
10890
11795
|
description = "The PDF file could not be loaded. It may be corrupted or in an unsupported format.";
|
|
10891
|
-
icon = /* @__PURE__ */ (0,
|
|
11796
|
+
icon = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("svg", { className: "w-12 h-12 text-red-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10892
11797
|
"path",
|
|
10893
11798
|
{
|
|
10894
11799
|
strokeLinecap: "round",
|
|
@@ -10900,7 +11805,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10900
11805
|
} else if (isNetworkError) {
|
|
10901
11806
|
title = "Network error";
|
|
10902
11807
|
description = "Unable to fetch the PDF file. Please check your internet connection and try again.";
|
|
10903
|
-
icon = /* @__PURE__ */ (0,
|
|
11808
|
+
icon = /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("svg", { className: "w-12 h-12 text-red-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10904
11809
|
"path",
|
|
10905
11810
|
{
|
|
10906
11811
|
strokeLinecap: "round",
|
|
@@ -10910,7 +11815,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10910
11815
|
}
|
|
10911
11816
|
) });
|
|
10912
11817
|
}
|
|
10913
|
-
return /* @__PURE__ */ (0,
|
|
11818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
10914
11819
|
"div",
|
|
10915
11820
|
{
|
|
10916
11821
|
className: cn(
|
|
@@ -10923,14 +11828,14 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10923
11828
|
),
|
|
10924
11829
|
children: [
|
|
10925
11830
|
icon,
|
|
10926
|
-
/* @__PURE__ */ (0,
|
|
10927
|
-
/* @__PURE__ */ (0,
|
|
10928
|
-
/* @__PURE__ */ (0,
|
|
10929
|
-
/* @__PURE__ */ (0,
|
|
10930
|
-
/* @__PURE__ */ (0,
|
|
11831
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h2", { className: "mt-4 text-xl font-semibold text-gray-900 dark:text-gray-100", children: title }),
|
|
11832
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "mt-2 text-sm text-gray-600 dark:text-gray-400 max-w-md", children: description }),
|
|
11833
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("details", { className: "mt-4 text-left max-w-md w-full", children: [
|
|
11834
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("summary", { className: "cursor-pointer text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200", children: "Technical details" }),
|
|
11835
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("pre", { className: "mt-2 p-2 bg-gray-100 dark:bg-gray-800 rounded text-xs overflow-auto", children: error.stack || error.message })
|
|
10931
11836
|
] }),
|
|
10932
|
-
/* @__PURE__ */ (0,
|
|
10933
|
-
/* @__PURE__ */ (0,
|
|
11837
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mt-6 flex gap-3", children: [
|
|
11838
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10934
11839
|
"button",
|
|
10935
11840
|
{
|
|
10936
11841
|
onClick: onReset,
|
|
@@ -10944,7 +11849,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10944
11849
|
children: "Try again"
|
|
10945
11850
|
}
|
|
10946
11851
|
),
|
|
10947
|
-
/* @__PURE__ */ (0,
|
|
11852
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
10948
11853
|
"button",
|
|
10949
11854
|
{
|
|
10950
11855
|
onClick: () => window.location.reload(),
|
|
@@ -10964,7 +11869,7 @@ function DefaultErrorUI({ error, onReset, className }) {
|
|
|
10964
11869
|
);
|
|
10965
11870
|
}
|
|
10966
11871
|
function withErrorBoundary({ component, ...props }) {
|
|
10967
|
-
return /* @__PURE__ */ (0,
|
|
11872
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PDFErrorBoundary, { ...props, children: component });
|
|
10968
11873
|
}
|
|
10969
11874
|
|
|
10970
11875
|
// src/index.ts
|
|
@@ -10999,6 +11904,7 @@ init_utils();
|
|
|
10999
11904
|
OutlinePanel,
|
|
11000
11905
|
PDFErrorBoundary,
|
|
11001
11906
|
PDFPage,
|
|
11907
|
+
PDFThumbnailNav,
|
|
11002
11908
|
PDFViewer,
|
|
11003
11909
|
PDFViewerClient,
|
|
11004
11910
|
PDFViewerContext,
|
|
@@ -11017,9 +11923,11 @@ init_utils();
|
|
|
11017
11923
|
ThumbnailPanel,
|
|
11018
11924
|
Toolbar,
|
|
11019
11925
|
VirtualizedDocumentContainer,
|
|
11926
|
+
applyRotation,
|
|
11020
11927
|
clearHighlights,
|
|
11021
11928
|
clearStudentData,
|
|
11022
11929
|
cn,
|
|
11930
|
+
countTextOnPage,
|
|
11023
11931
|
createAgentAPI,
|
|
11024
11932
|
createAgentStore,
|
|
11025
11933
|
createAnnotationStore,
|
|
@@ -11028,6 +11936,7 @@ init_utils();
|
|
|
11028
11936
|
createSearchStore,
|
|
11029
11937
|
createStudentStore,
|
|
11030
11938
|
createViewerStore,
|
|
11939
|
+
doRectsIntersect,
|
|
11031
11940
|
downloadAnnotationsAsJSON,
|
|
11032
11941
|
downloadAnnotationsAsMarkdown,
|
|
11033
11942
|
downloadFile,
|
|
@@ -11035,25 +11944,39 @@ init_utils();
|
|
|
11035
11944
|
exportAnnotationsAsMarkdown,
|
|
11036
11945
|
exportHighlightsAsJSON,
|
|
11037
11946
|
exportHighlightsAsMarkdown,
|
|
11947
|
+
extractPageText,
|
|
11948
|
+
findTextInDocument,
|
|
11949
|
+
findTextOnPage,
|
|
11038
11950
|
generateDocumentId,
|
|
11039
11951
|
getAllDocumentIds,
|
|
11040
11952
|
getAllStudentDataDocumentIds,
|
|
11041
11953
|
getMetadata,
|
|
11042
11954
|
getOutline,
|
|
11043
11955
|
getPage,
|
|
11956
|
+
getPageText,
|
|
11044
11957
|
getPageTextContent,
|
|
11045
11958
|
getPluginManager,
|
|
11959
|
+
getRectIntersection,
|
|
11960
|
+
getRotatedDimensions,
|
|
11046
11961
|
getStorageStats,
|
|
11047
11962
|
importHighlightsFromJSON,
|
|
11048
11963
|
initializePDFJS,
|
|
11049
11964
|
isPDFJSInitialized,
|
|
11965
|
+
isPointInRect,
|
|
11050
11966
|
loadDocument,
|
|
11051
11967
|
loadHighlights,
|
|
11052
11968
|
loadStudentData,
|
|
11969
|
+
mergeAdjacentRects,
|
|
11970
|
+
pdfToPercent,
|
|
11971
|
+
pdfToViewport,
|
|
11053
11972
|
pdfjsLib,
|
|
11973
|
+
percentToPDF,
|
|
11974
|
+
percentToViewport,
|
|
11054
11975
|
quickViewer,
|
|
11976
|
+
removeRotation,
|
|
11055
11977
|
saveHighlights,
|
|
11056
11978
|
saveStudentData,
|
|
11979
|
+
scaleRect,
|
|
11057
11980
|
useAgentContext,
|
|
11058
11981
|
useAgentStore,
|
|
11059
11982
|
useAnnotationStore,
|
|
@@ -11075,6 +11998,8 @@ init_utils();
|
|
|
11075
11998
|
useTouchGestures,
|
|
11076
11999
|
useViewerStore,
|
|
11077
12000
|
useZoom,
|
|
12001
|
+
viewportToPDF,
|
|
12002
|
+
viewportToPercent,
|
|
11078
12003
|
withErrorBoundary
|
|
11079
12004
|
});
|
|
11080
12005
|
//# sourceMappingURL=index.cjs.map
|