@papyrus-sdk/ui-react 0.2.19 → 0.2.21
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.js +527 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +535 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// components/Topbar.tsx
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { useViewerStore } from "@papyrus-sdk/core";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -17,6 +17,7 @@ var Topbar = ({
|
|
|
17
17
|
showUpload = true,
|
|
18
18
|
showSearch = true
|
|
19
19
|
}) => {
|
|
20
|
+
const viewerState = useViewerStore();
|
|
20
21
|
const {
|
|
21
22
|
currentPage,
|
|
22
23
|
pageCount,
|
|
@@ -29,13 +30,15 @@ var Topbar = ({
|
|
|
29
30
|
toggleSidebarLeft,
|
|
30
31
|
toggleSidebarRight,
|
|
31
32
|
triggerScrollToPage
|
|
32
|
-
} =
|
|
33
|
+
} = viewerState;
|
|
34
|
+
const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
|
|
33
35
|
const fileInputRef = useRef(null);
|
|
34
36
|
const zoomTimerRef = useRef(null);
|
|
35
37
|
const pendingZoomRef = useRef(null);
|
|
36
38
|
const [pageInput, setPageInput] = useState(currentPage.toString());
|
|
37
39
|
const [showPageThemes, setShowPageThemes] = useState(false);
|
|
38
40
|
const [showMobileMenu, setShowMobileMenu] = useState(false);
|
|
41
|
+
const [isMobileViewport, setIsMobileViewport] = useState(false);
|
|
39
42
|
const pageDigits = Math.max(2, String(pageCount || 1).length);
|
|
40
43
|
const isDark = uiTheme === "dark";
|
|
41
44
|
const canUseDOM = typeof document !== "undefined";
|
|
@@ -52,6 +55,18 @@ var Topbar = ({
|
|
|
52
55
|
useEffect(() => {
|
|
53
56
|
if (!hasMobileMenu) setShowMobileMenu(false);
|
|
54
57
|
}, [hasMobileMenu]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!canUseDOM || typeof window.matchMedia !== "function") return;
|
|
60
|
+
const mediaQuery = window.matchMedia("(max-width: 639px)");
|
|
61
|
+
const updateViewport = () => setIsMobileViewport(mediaQuery.matches);
|
|
62
|
+
updateViewport();
|
|
63
|
+
if (typeof mediaQuery.addEventListener === "function") {
|
|
64
|
+
mediaQuery.addEventListener("change", updateViewport);
|
|
65
|
+
return () => mediaQuery.removeEventListener("change", updateViewport);
|
|
66
|
+
}
|
|
67
|
+
mediaQuery.addListener(updateViewport);
|
|
68
|
+
return () => mediaQuery.removeListener(updateViewport);
|
|
69
|
+
}, [canUseDOM]);
|
|
55
70
|
useEffect(() => {
|
|
56
71
|
if (!showMobileMenu || !canUseDOM) return;
|
|
57
72
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -65,6 +80,30 @@ var Topbar = ({
|
|
|
65
80
|
window.removeEventListener("keydown", handleKeyDown);
|
|
66
81
|
};
|
|
67
82
|
}, [showMobileMenu, canUseDOM]);
|
|
83
|
+
const topbarStyle = useMemo(() => {
|
|
84
|
+
const mergedStyle = { ...style ?? {} };
|
|
85
|
+
if (!isMobileViewport) {
|
|
86
|
+
mergedStyle.transition = "height 180ms ease, opacity 160ms ease, padding 180ms ease, border-width 180ms ease";
|
|
87
|
+
return mergedStyle;
|
|
88
|
+
}
|
|
89
|
+
mergedStyle.transition = "height 180ms ease, opacity 160ms ease, padding 180ms ease, border-width 180ms ease";
|
|
90
|
+
mergedStyle.overflow = "hidden";
|
|
91
|
+
if (!mobileTopbarVisible) {
|
|
92
|
+
mergedStyle.height = 0;
|
|
93
|
+
mergedStyle.minHeight = 0;
|
|
94
|
+
mergedStyle.paddingTop = 0;
|
|
95
|
+
mergedStyle.paddingBottom = 0;
|
|
96
|
+
mergedStyle.borderBottomWidth = 0;
|
|
97
|
+
mergedStyle.opacity = 0;
|
|
98
|
+
mergedStyle.pointerEvents = "none";
|
|
99
|
+
return mergedStyle;
|
|
100
|
+
}
|
|
101
|
+
mergedStyle.height = 56;
|
|
102
|
+
mergedStyle.minHeight = 56;
|
|
103
|
+
mergedStyle.opacity = 1;
|
|
104
|
+
mergedStyle.pointerEvents = "auto";
|
|
105
|
+
return mergedStyle;
|
|
106
|
+
}, [isMobileViewport, mobileTopbarVisible, style]);
|
|
68
107
|
const handleZoom = (delta) => {
|
|
69
108
|
const baseZoom = pendingZoomRef.current ?? zoom;
|
|
70
109
|
const nextZoom = Math.max(0.2, Math.min(5, baseZoom + delta));
|
|
@@ -355,7 +394,7 @@ var Topbar = ({
|
|
|
355
394
|
{
|
|
356
395
|
"data-papyrus-theme": uiTheme,
|
|
357
396
|
className: `papyrus-topbar papyrus-theme relative h-14 border-b flex items-center px-3 sm:px-4 z-50 transition-colors duration-200 ${isDark ? "bg-[#1a1a1a] border-[#333] text-white" : "bg-white border-gray-200 text-gray-800"}`,
|
|
358
|
-
style,
|
|
397
|
+
style: topbarStyle,
|
|
359
398
|
children: [
|
|
360
399
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0 z-10", children: [
|
|
361
400
|
showSidebarLeftToggle && /* @__PURE__ */ jsx(
|
|
@@ -1063,10 +1102,15 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1063
1102
|
setDocumentState,
|
|
1064
1103
|
triggerScrollToPage,
|
|
1065
1104
|
annotations,
|
|
1066
|
-
accentColor
|
|
1105
|
+
accentColor,
|
|
1106
|
+
updateAnnotation,
|
|
1107
|
+
addAnnotationReply,
|
|
1108
|
+
setSelectedAnnotation
|
|
1067
1109
|
} = useViewerStore3();
|
|
1068
1110
|
const [query, setQuery] = useState3("");
|
|
1069
1111
|
const [isSearching, setIsSearching] = useState3(false);
|
|
1112
|
+
const [contentDrafts, setContentDrafts] = useState3({});
|
|
1113
|
+
const [replyDrafts, setReplyDrafts] = useState3({});
|
|
1070
1114
|
const searchService = new SearchService(engine);
|
|
1071
1115
|
const isDark = uiTheme === "dark";
|
|
1072
1116
|
const accentSoft = withAlpha2(accentColor, 0.12);
|
|
@@ -1082,6 +1126,41 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1082
1126
|
setSearch(query, results);
|
|
1083
1127
|
setIsSearching(false);
|
|
1084
1128
|
};
|
|
1129
|
+
const jumpToAnnotation = (annotation) => {
|
|
1130
|
+
const page = annotation.pageIndex + 1;
|
|
1131
|
+
engine.goToPage(page);
|
|
1132
|
+
setDocumentState({ currentPage: page });
|
|
1133
|
+
setSelectedAnnotation(annotation.id);
|
|
1134
|
+
triggerScrollToPage(annotation.pageIndex);
|
|
1135
|
+
};
|
|
1136
|
+
const getContentDraft = (annotation) => {
|
|
1137
|
+
if (Object.prototype.hasOwnProperty.call(contentDrafts, annotation.id)) {
|
|
1138
|
+
return contentDrafts[annotation.id];
|
|
1139
|
+
}
|
|
1140
|
+
return annotation.content ?? "";
|
|
1141
|
+
};
|
|
1142
|
+
const updateContentDraft = (annotationId, nextValue) => {
|
|
1143
|
+
setContentDrafts((prev) => ({ ...prev, [annotationId]: nextValue }));
|
|
1144
|
+
};
|
|
1145
|
+
const submitContent = (annotation) => {
|
|
1146
|
+
const nextContent = getContentDraft(annotation).trim();
|
|
1147
|
+
const currentContent = (annotation.content ?? "").trim();
|
|
1148
|
+
if (nextContent === currentContent) return;
|
|
1149
|
+
updateAnnotation(annotation.id, {
|
|
1150
|
+
content: nextContent,
|
|
1151
|
+
updatedAt: Date.now()
|
|
1152
|
+
});
|
|
1153
|
+
};
|
|
1154
|
+
const getReplyDraft = (annotationId) => replyDrafts[annotationId] ?? "";
|
|
1155
|
+
const updateReplyDraft = (annotationId, nextValue) => {
|
|
1156
|
+
setReplyDrafts((prev) => ({ ...prev, [annotationId]: nextValue }));
|
|
1157
|
+
};
|
|
1158
|
+
const submitReply = (annotationId) => {
|
|
1159
|
+
const nextReply = getReplyDraft(annotationId).trim();
|
|
1160
|
+
if (!nextReply) return;
|
|
1161
|
+
addAnnotationReply(annotationId, nextReply);
|
|
1162
|
+
setReplyDrafts((prev) => ({ ...prev, [annotationId]: "" }));
|
|
1163
|
+
};
|
|
1085
1164
|
if (!sidebarRightOpen) return null;
|
|
1086
1165
|
return /* @__PURE__ */ jsxs3(
|
|
1087
1166
|
"div",
|
|
@@ -1283,48 +1362,152 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1283
1362
|
}
|
|
1284
1363
|
) }),
|
|
1285
1364
|
/* @__PURE__ */ jsx3("p", { className: "text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Sem anota\xE7\xF5es" })
|
|
1286
|
-
] }) : annotations.
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1365
|
+
] }) : annotations.slice().sort(
|
|
1366
|
+
(a, b) => (b.updatedAt ?? b.createdAt) - (a.updatedAt ?? a.createdAt)
|
|
1367
|
+
).map((ann) => {
|
|
1368
|
+
const isCommentThread = ann.type === "comment" || ann.type === "text";
|
|
1369
|
+
const replies = ann.replies ?? [];
|
|
1370
|
+
const contentDraft = getContentDraft(ann);
|
|
1371
|
+
const replyDraft = getReplyDraft(ann.id);
|
|
1372
|
+
const hasExistingContent = Boolean((ann.content ?? "").trim());
|
|
1373
|
+
return /* @__PURE__ */ jsxs3(
|
|
1374
|
+
"div",
|
|
1375
|
+
{
|
|
1376
|
+
className: "rounded-xl border p-4 transition-colors",
|
|
1377
|
+
style: {
|
|
1378
|
+
background: "var(--papyrus-surface-2-resolved, var(--papyrus-surface-2, #1f2937))",
|
|
1379
|
+
borderColor: "var(--papyrus-border-resolved, var(--papyrus-border, #374151))",
|
|
1380
|
+
color: "var(--papyrus-text-resolved, var(--papyrus-text, #e5e7eb))"
|
|
1381
|
+
},
|
|
1382
|
+
children: [
|
|
1383
|
+
/* @__PURE__ */ jsxs3("div", { className: "mb-3 flex items-center justify-between", children: [
|
|
1384
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
|
|
1385
|
+
/* @__PURE__ */ jsx3(
|
|
1386
|
+
"div",
|
|
1387
|
+
{
|
|
1388
|
+
className: "h-2.5 w-2.5 rounded-full",
|
|
1389
|
+
style: { backgroundColor: ann.color }
|
|
1390
|
+
}
|
|
1391
|
+
),
|
|
1392
|
+
/* @__PURE__ */ jsxs3(
|
|
1393
|
+
"span",
|
|
1394
|
+
{
|
|
1395
|
+
className: "text-[10px] font-black uppercase tracking-wide",
|
|
1396
|
+
style: { color: accentColor },
|
|
1397
|
+
children: [
|
|
1398
|
+
"P",
|
|
1399
|
+
ann.pageIndex + 1
|
|
1400
|
+
]
|
|
1401
|
+
}
|
|
1402
|
+
),
|
|
1403
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[10px] font-semibold opacity-70 uppercase tracking-wide", children: ann.type })
|
|
1404
|
+
] }),
|
|
1293
1405
|
/* @__PURE__ */ jsx3(
|
|
1294
|
-
"
|
|
1406
|
+
"button",
|
|
1407
|
+
{
|
|
1408
|
+
type: "button",
|
|
1409
|
+
className: "rounded-md border px-2 py-1 text-[10px] font-semibold uppercase tracking-wide",
|
|
1410
|
+
onClick: () => jumpToAnnotation(ann),
|
|
1411
|
+
style: {
|
|
1412
|
+
borderColor: accentColor,
|
|
1413
|
+
color: accentColor
|
|
1414
|
+
},
|
|
1415
|
+
children: "Ir para pagina"
|
|
1416
|
+
}
|
|
1417
|
+
)
|
|
1418
|
+
] }),
|
|
1419
|
+
isCommentThread ? /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
1420
|
+
/* @__PURE__ */ jsx3(
|
|
1421
|
+
"textarea",
|
|
1295
1422
|
{
|
|
1296
|
-
className: "w-
|
|
1297
|
-
style: {
|
|
1423
|
+
className: "w-full resize-none rounded-md border p-2 text-xs focus:outline-none",
|
|
1424
|
+
style: {
|
|
1425
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #111827))",
|
|
1426
|
+
borderColor: "var(--papyrus-border-resolved, var(--papyrus-border, #374151))",
|
|
1427
|
+
color: "var(--papyrus-text-resolved, var(--papyrus-text, #e5e7eb))"
|
|
1428
|
+
},
|
|
1429
|
+
rows: 3,
|
|
1430
|
+
placeholder: "Escreva seu comentario...",
|
|
1431
|
+
value: contentDraft,
|
|
1432
|
+
onChange: (event) => updateContentDraft(ann.id, event.target.value),
|
|
1433
|
+
onKeyDown: (event) => {
|
|
1434
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
1435
|
+
event.preventDefault();
|
|
1436
|
+
submitContent(ann);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1298
1439
|
}
|
|
1299
1440
|
),
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
"
|
|
1441
|
+
/* @__PURE__ */ jsx3("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx3(
|
|
1442
|
+
"button",
|
|
1302
1443
|
{
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1444
|
+
type: "button",
|
|
1445
|
+
className: "rounded-md px-3 py-1.5 text-[11px] font-semibold text-white",
|
|
1446
|
+
style: { backgroundColor: accentColor },
|
|
1447
|
+
onClick: () => submitContent(ann),
|
|
1448
|
+
children: hasExistingContent ? "Atualizar comentario" : "Enviar comentario"
|
|
1449
|
+
}
|
|
1450
|
+
) })
|
|
1451
|
+
] }) : null,
|
|
1452
|
+
replies.length > 0 ? /* @__PURE__ */ jsx3("div", { className: "mt-3 space-y-2", children: replies.map((reply) => /* @__PURE__ */ jsxs3(
|
|
1453
|
+
"div",
|
|
1454
|
+
{
|
|
1455
|
+
className: "rounded-md border p-2",
|
|
1456
|
+
style: {
|
|
1457
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #111827))",
|
|
1458
|
+
borderColor: "var(--papyrus-border-resolved, var(--papyrus-border, #374151))"
|
|
1459
|
+
},
|
|
1460
|
+
children: [
|
|
1461
|
+
/* @__PURE__ */ jsx3("p", { className: "text-xs leading-relaxed", children: reply.content }),
|
|
1462
|
+
/* @__PURE__ */ jsx3("p", { className: "mt-1 text-[10px] opacity-70", children: new Date(reply.createdAt).toLocaleTimeString(
|
|
1463
|
+
[],
|
|
1464
|
+
{
|
|
1465
|
+
hour: "2-digit",
|
|
1466
|
+
minute: "2-digit"
|
|
1467
|
+
}
|
|
1468
|
+
) })
|
|
1469
|
+
]
|
|
1470
|
+
},
|
|
1471
|
+
reply.id
|
|
1472
|
+
)) }) : null,
|
|
1473
|
+
isCommentThread ? /* @__PURE__ */ jsxs3("div", { className: "mt-3 flex items-center gap-2", children: [
|
|
1474
|
+
/* @__PURE__ */ jsx3(
|
|
1475
|
+
"input",
|
|
1476
|
+
{
|
|
1477
|
+
type: "text",
|
|
1478
|
+
className: "flex-1 rounded-md border px-2 py-1.5 text-xs focus:outline-none",
|
|
1479
|
+
style: {
|
|
1480
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #111827))",
|
|
1481
|
+
borderColor: "var(--papyrus-border-resolved, var(--papyrus-border, #374151))",
|
|
1482
|
+
color: "var(--papyrus-text-resolved, var(--papyrus-text, #e5e7eb))"
|
|
1483
|
+
},
|
|
1484
|
+
value: replyDraft,
|
|
1485
|
+
placeholder: "Responder...",
|
|
1486
|
+
onChange: (event) => updateReplyDraft(ann.id, event.target.value),
|
|
1487
|
+
onKeyDown: (event) => {
|
|
1488
|
+
if (event.key === "Enter") {
|
|
1489
|
+
event.preventDefault();
|
|
1490
|
+
submitReply(ann.id);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
),
|
|
1495
|
+
/* @__PURE__ */ jsx3(
|
|
1496
|
+
"button",
|
|
1497
|
+
{
|
|
1498
|
+
type: "button",
|
|
1499
|
+
className: "rounded-md px-3 py-1.5 text-[11px] font-semibold text-white",
|
|
1500
|
+
style: { backgroundColor: accentColor },
|
|
1501
|
+
onClick: () => submitReply(ann.id),
|
|
1502
|
+
children: "Responder"
|
|
1309
1503
|
}
|
|
1310
1504
|
)
|
|
1311
|
-
] })
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
/* @__PURE__ */ jsx3(
|
|
1318
|
-
"p",
|
|
1319
|
-
{
|
|
1320
|
-
className: `text-[11px] font-bold uppercase tracking-tight ${isDark ? "text-gray-200" : "text-gray-700"}`,
|
|
1321
|
-
children: ann.type
|
|
1322
|
-
}
|
|
1323
|
-
)
|
|
1324
|
-
]
|
|
1325
|
-
},
|
|
1326
|
-
ann.id
|
|
1327
|
-
))
|
|
1505
|
+
] }) : null
|
|
1506
|
+
]
|
|
1507
|
+
},
|
|
1508
|
+
ann.id
|
|
1509
|
+
);
|
|
1510
|
+
})
|
|
1328
1511
|
] }) })
|
|
1329
1512
|
]
|
|
1330
1513
|
}
|
|
@@ -1333,11 +1516,11 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1333
1516
|
var SidebarRight_default = SidebarRight;
|
|
1334
1517
|
|
|
1335
1518
|
// components/Viewer.tsx
|
|
1336
|
-
import { useEffect as useEffect4, useMemo as
|
|
1519
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState5 } from "react";
|
|
1337
1520
|
import { useViewerStore as useViewerStore5 } from "@papyrus-sdk/core";
|
|
1338
1521
|
|
|
1339
1522
|
// components/PageRenderer.tsx
|
|
1340
|
-
import { useEffect as useEffect3, useMemo, useRef as useRef3, useState as useState4 } from "react";
|
|
1523
|
+
import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
|
|
1341
1524
|
import { useViewerStore as useViewerStore4, papyrusEvents } from "@papyrus-sdk/core";
|
|
1342
1525
|
import {
|
|
1343
1526
|
PapyrusEventType
|
|
@@ -1354,6 +1537,10 @@ var PageRenderer = ({
|
|
|
1354
1537
|
const canvasRef = useRef3(null);
|
|
1355
1538
|
const htmlLayerRef = useRef3(null);
|
|
1356
1539
|
const textLayerRef = useRef3(null);
|
|
1540
|
+
const skipNextAnnotationSelectRef = useRef3(false);
|
|
1541
|
+
const skipSelectResetTimerRef = useRef3(
|
|
1542
|
+
null
|
|
1543
|
+
);
|
|
1357
1544
|
const [loading, setLoading] = useState4(true);
|
|
1358
1545
|
const [pageSize, setPageSize] = useState4(null);
|
|
1359
1546
|
const [isDragging, setIsDragging] = useState4(false);
|
|
@@ -1371,6 +1558,8 @@ var PageRenderer = ({
|
|
|
1371
1558
|
setDocumentState,
|
|
1372
1559
|
annotations,
|
|
1373
1560
|
addAnnotation,
|
|
1561
|
+
addAnnotationReply,
|
|
1562
|
+
updateAnnotation,
|
|
1374
1563
|
activeTool,
|
|
1375
1564
|
removeAnnotation,
|
|
1376
1565
|
selectedAnnotationId,
|
|
@@ -1390,10 +1579,28 @@ var PageRenderer = ({
|
|
|
1390
1579
|
"strikeout"
|
|
1391
1580
|
]);
|
|
1392
1581
|
const canSelectText = activeTool === "select" || textMarkupTools.has(activeTool);
|
|
1393
|
-
const hasSearchHits =
|
|
1582
|
+
const hasSearchHits = useMemo2(
|
|
1394
1583
|
() => Boolean(searchQuery?.trim()) && searchResults.some((res) => res.pageIndex === pageIndex),
|
|
1395
1584
|
[searchQuery, searchResults, pageIndex]
|
|
1396
1585
|
);
|
|
1586
|
+
const suppressNextAnnotationSelect = () => {
|
|
1587
|
+
skipNextAnnotationSelectRef.current = true;
|
|
1588
|
+
if (skipSelectResetTimerRef.current) {
|
|
1589
|
+
clearTimeout(skipSelectResetTimerRef.current);
|
|
1590
|
+
}
|
|
1591
|
+
skipSelectResetTimerRef.current = setTimeout(() => {
|
|
1592
|
+
skipNextAnnotationSelectRef.current = false;
|
|
1593
|
+
skipSelectResetTimerRef.current = null;
|
|
1594
|
+
}, 0);
|
|
1595
|
+
};
|
|
1596
|
+
useEffect3(
|
|
1597
|
+
() => () => {
|
|
1598
|
+
if (skipSelectResetTimerRef.current) {
|
|
1599
|
+
clearTimeout(skipSelectResetTimerRef.current);
|
|
1600
|
+
}
|
|
1601
|
+
},
|
|
1602
|
+
[]
|
|
1603
|
+
);
|
|
1397
1604
|
useEffect3(() => {
|
|
1398
1605
|
let active = true;
|
|
1399
1606
|
const loadSize = async () => {
|
|
@@ -1411,14 +1618,14 @@ var PageRenderer = ({
|
|
|
1411
1618
|
active = false;
|
|
1412
1619
|
};
|
|
1413
1620
|
}, [engine, pageIndex]);
|
|
1414
|
-
const fitScale =
|
|
1621
|
+
const fitScale = useMemo2(() => {
|
|
1415
1622
|
if (!availableWidth || !pageSize?.width) return 1;
|
|
1416
1623
|
const targetWidth = Math.max(0, availableWidth - 48);
|
|
1417
1624
|
if (!targetWidth) return 1;
|
|
1418
1625
|
const rawScale = Math.min(1, targetWidth / pageSize.width);
|
|
1419
1626
|
return Math.round(rawScale * SCALE_PRECISION) / SCALE_PRECISION;
|
|
1420
1627
|
}, [availableWidth, pageSize]);
|
|
1421
|
-
const displaySize =
|
|
1628
|
+
const displaySize = useMemo2(() => {
|
|
1422
1629
|
if (!pageSize) return null;
|
|
1423
1630
|
const scale = zoom * fitScale;
|
|
1424
1631
|
return {
|
|
@@ -1564,6 +1771,16 @@ var PageRenderer = ({
|
|
|
1564
1771
|
textLayerVersion
|
|
1565
1772
|
]);
|
|
1566
1773
|
const handleMouseDown = (e) => {
|
|
1774
|
+
const target = e.target;
|
|
1775
|
+
const clickedInsideAnnotation = Boolean(
|
|
1776
|
+
target?.closest("[data-papyrus-annotation-id]")
|
|
1777
|
+
);
|
|
1778
|
+
const clickedSelectionMenu = Boolean(
|
|
1779
|
+
target?.closest("[data-papyrus-selection-menu]")
|
|
1780
|
+
);
|
|
1781
|
+
if (!clickedInsideAnnotation && !clickedSelectionMenu) {
|
|
1782
|
+
setSelectedAnnotation(null);
|
|
1783
|
+
}
|
|
1567
1784
|
setSelectionMenu(null);
|
|
1568
1785
|
if (activeTool === "ink") {
|
|
1569
1786
|
const rect2 = containerRef.current?.getBoundingClientRect();
|
|
@@ -1620,6 +1837,7 @@ var PageRenderer = ({
|
|
|
1620
1837
|
x: Math.max(0, Math.min(1, p.x)),
|
|
1621
1838
|
y: Math.max(0, Math.min(1, p.y))
|
|
1622
1839
|
}));
|
|
1840
|
+
suppressNextAnnotationSelect();
|
|
1623
1841
|
addAnnotation({
|
|
1624
1842
|
id: Math.random().toString(36).substr(2, 9),
|
|
1625
1843
|
pageIndex,
|
|
@@ -1700,6 +1918,7 @@ var PageRenderer = ({
|
|
|
1700
1918
|
height: Math.max(...ye) - Math.min(...ys)
|
|
1701
1919
|
};
|
|
1702
1920
|
if (textMarkupTools.has(activeTool)) {
|
|
1921
|
+
suppressNextAnnotationSelect();
|
|
1703
1922
|
addAnnotation({
|
|
1704
1923
|
id: Math.random().toString(36).substr(2, 9),
|
|
1705
1924
|
pageIndex,
|
|
@@ -1735,6 +1954,9 @@ var PageRenderer = ({
|
|
|
1735
1954
|
if (currentRect.w > 5 && currentRect.h > 5) {
|
|
1736
1955
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
1737
1956
|
if (rect) {
|
|
1957
|
+
if (activeTool !== "text" && activeTool !== "comment") {
|
|
1958
|
+
suppressNextAnnotationSelect();
|
|
1959
|
+
}
|
|
1738
1960
|
addAnnotation({
|
|
1739
1961
|
id: Math.random().toString(36).substr(2, 9),
|
|
1740
1962
|
pageIndex,
|
|
@@ -1858,6 +2080,7 @@ var PageRenderer = ({
|
|
|
1858
2080
|
selectionMenu && /* @__PURE__ */ jsx4(
|
|
1859
2081
|
"div",
|
|
1860
2082
|
{
|
|
2083
|
+
"data-papyrus-selection-menu": "true",
|
|
1861
2084
|
className: "absolute z-[60] flex items-center gap-1 rounded-full border px-2 py-1 shadow-xl bg-white/95 backdrop-blur-md text-gray-700",
|
|
1862
2085
|
style: { left: selectionMenu.anchor.x, top: selectionMenu.anchor.y },
|
|
1863
2086
|
children: [
|
|
@@ -1870,6 +2093,7 @@ var PageRenderer = ({
|
|
|
1870
2093
|
{
|
|
1871
2094
|
className: "text-[10px] font-bold px-2 py-1 rounded-full hover:bg-gray-100",
|
|
1872
2095
|
onClick: () => {
|
|
2096
|
+
suppressNextAnnotationSelect();
|
|
1873
2097
|
addAnnotation({
|
|
1874
2098
|
id: Math.random().toString(36).substr(2, 9),
|
|
1875
2099
|
pageIndex,
|
|
@@ -1896,7 +2120,15 @@ var PageRenderer = ({
|
|
|
1896
2120
|
isSelected: selectedAnnotationId === ann.id,
|
|
1897
2121
|
accentColor,
|
|
1898
2122
|
onDelete: () => removeAnnotation(ann.id),
|
|
1899
|
-
onSelect: () =>
|
|
2123
|
+
onSelect: () => {
|
|
2124
|
+
if (skipNextAnnotationSelectRef.current) {
|
|
2125
|
+
skipNextAnnotationSelectRef.current = false;
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
setSelectedAnnotation(ann.id);
|
|
2129
|
+
},
|
|
2130
|
+
onUpdate: (updates) => updateAnnotation(ann.id, updates),
|
|
2131
|
+
onAddReply: (content) => addAnnotationReply(ann.id, content)
|
|
1900
2132
|
},
|
|
1901
2133
|
ann.id
|
|
1902
2134
|
)) })
|
|
@@ -1904,12 +2136,43 @@ var PageRenderer = ({
|
|
|
1904
2136
|
}
|
|
1905
2137
|
);
|
|
1906
2138
|
};
|
|
1907
|
-
var AnnotationItem = ({
|
|
2139
|
+
var AnnotationItem = ({
|
|
2140
|
+
ann,
|
|
2141
|
+
isSelected,
|
|
2142
|
+
accentColor,
|
|
2143
|
+
onDelete,
|
|
2144
|
+
onSelect,
|
|
2145
|
+
onUpdate,
|
|
2146
|
+
onAddReply
|
|
2147
|
+
}) => {
|
|
1908
2148
|
const isText = ann.type === "text" || ann.type === "comment";
|
|
1909
2149
|
const isHighlight = ann.type === "highlight";
|
|
1910
2150
|
const isMarkup = ann.type === "highlight" || ann.type === "underline" || ann.type === "squiggly" || ann.type === "strikeout";
|
|
1911
2151
|
const rects = ann.rects && ann.rects.length > 0 ? ann.rects : [ann.rect];
|
|
1912
2152
|
const isInk = ann.type === "ink" && ann.path && ann.path.length > 1;
|
|
2153
|
+
const [draftContent, setDraftContent] = useState4(ann.content ?? "");
|
|
2154
|
+
const [draftReply, setDraftReply] = useState4("");
|
|
2155
|
+
useEffect3(() => {
|
|
2156
|
+
setDraftContent(ann.content ?? "");
|
|
2157
|
+
}, [ann.id, ann.content]);
|
|
2158
|
+
useEffect3(() => {
|
|
2159
|
+
setDraftReply("");
|
|
2160
|
+
}, [ann.id]);
|
|
2161
|
+
const handleSaveContent = () => {
|
|
2162
|
+
const nextContent = draftContent.trim();
|
|
2163
|
+
const currentContent = (ann.content ?? "").trim();
|
|
2164
|
+
if (nextContent === currentContent) return;
|
|
2165
|
+
onUpdate({
|
|
2166
|
+
content: nextContent,
|
|
2167
|
+
updatedAt: Date.now()
|
|
2168
|
+
});
|
|
2169
|
+
};
|
|
2170
|
+
const handleReplySubmit = () => {
|
|
2171
|
+
const nextReply = draftReply.trim();
|
|
2172
|
+
if (!nextReply) return;
|
|
2173
|
+
onAddReply(nextReply);
|
|
2174
|
+
setDraftReply("");
|
|
2175
|
+
};
|
|
1913
2176
|
const renderMarkupRects = () => {
|
|
1914
2177
|
if (!isMarkup) return null;
|
|
1915
2178
|
return rects.map((r, idx) => {
|
|
@@ -2014,6 +2277,7 @@ var AnnotationItem = ({ ann, isSelected, accentColor, onDelete, onSelect }) => {
|
|
|
2014
2277
|
return /* @__PURE__ */ jsxs4(
|
|
2015
2278
|
"div",
|
|
2016
2279
|
{
|
|
2280
|
+
"data-papyrus-annotation-id": ann.id,
|
|
2017
2281
|
className: `absolute pointer-events-auto transition-all ${isSelected ? "shadow-xl z-30" : "z-10"}`,
|
|
2018
2282
|
style: {
|
|
2019
2283
|
left: `${ann.rect.x * 100}%`,
|
|
@@ -2032,16 +2296,151 @@ var AnnotationItem = ({ ann, isSelected, accentColor, onDelete, onSelect }) => {
|
|
|
2032
2296
|
children: [
|
|
2033
2297
|
renderMarkupRects(),
|
|
2034
2298
|
renderInk(),
|
|
2035
|
-
isText && isSelected && /* @__PURE__ */ jsx4(
|
|
2036
|
-
"
|
|
2299
|
+
isText && !isSelected && /* @__PURE__ */ jsx4(
|
|
2300
|
+
"button",
|
|
2037
2301
|
{
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2302
|
+
type: "button",
|
|
2303
|
+
className: "absolute -top-2 -right-2 h-6 w-6 rounded-full flex items-center justify-center shadow-lg",
|
|
2304
|
+
style: {
|
|
2305
|
+
background: "var(--papyrus-surface-2-resolved, var(--papyrus-surface-2, #1f2937))",
|
|
2306
|
+
border: "1px solid var(--papyrus-border-resolved, #374151)",
|
|
2307
|
+
color: "var(--papyrus-text-resolved, #e5e7eb)"
|
|
2308
|
+
},
|
|
2309
|
+
title: "Abrir comentario",
|
|
2310
|
+
"aria-label": "Abrir comentario",
|
|
2311
|
+
onClick: (event) => {
|
|
2312
|
+
event.stopPropagation();
|
|
2313
|
+
onSelect();
|
|
2314
|
+
},
|
|
2315
|
+
children: /* @__PURE__ */ jsx4(
|
|
2316
|
+
"svg",
|
|
2317
|
+
{
|
|
2318
|
+
className: "h-3.5 w-3.5",
|
|
2319
|
+
fill: "none",
|
|
2320
|
+
stroke: "currentColor",
|
|
2321
|
+
viewBox: "0 0 24 24",
|
|
2322
|
+
children: /* @__PURE__ */ jsx4(
|
|
2323
|
+
"path",
|
|
2324
|
+
{
|
|
2325
|
+
strokeLinecap: "round",
|
|
2326
|
+
strokeLinejoin: "round",
|
|
2327
|
+
strokeWidth: 2,
|
|
2328
|
+
d: "M8 10h.01M12 10h.01M16 10h.01M7 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-4l-4 4v-4z"
|
|
2329
|
+
}
|
|
2330
|
+
)
|
|
2331
|
+
}
|
|
2332
|
+
)
|
|
2043
2333
|
}
|
|
2044
|
-
)
|
|
2334
|
+
),
|
|
2335
|
+
isText && isSelected && /* @__PURE__ */ jsxs4(
|
|
2336
|
+
"div",
|
|
2337
|
+
{
|
|
2338
|
+
className: "absolute top-full mt-2 w-72 rounded-xl p-3 z-50",
|
|
2339
|
+
style: {
|
|
2340
|
+
background: "var(--papyrus-popover-resolved, var(--papyrus-popover, #ffffff))",
|
|
2341
|
+
border: "1px solid var(--papyrus-border-resolved, #d1d5db)",
|
|
2342
|
+
color: "var(--papyrus-text-resolved, #111827)",
|
|
2343
|
+
boxShadow: "0 20px 40px var(--papyrus-shadow-resolved, rgba(0, 0, 0, 0.3))"
|
|
2344
|
+
},
|
|
2345
|
+
onClick: (event) => event.stopPropagation(),
|
|
2346
|
+
children: [
|
|
2347
|
+
/* @__PURE__ */ jsxs4("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
2348
|
+
/* @__PURE__ */ jsx4("span", { className: "text-[10px] font-bold uppercase tracking-wider opacity-70", children: ann.type === "comment" ? "Comentario" : "Nota" }),
|
|
2349
|
+
ann.replies?.length ? /* @__PURE__ */ jsxs4("span", { className: "text-[10px] opacity-70", children: [
|
|
2350
|
+
ann.replies.length,
|
|
2351
|
+
" resposta",
|
|
2352
|
+
ann.replies.length > 1 ? "s" : ""
|
|
2353
|
+
] }) : null
|
|
2354
|
+
] }),
|
|
2355
|
+
/* @__PURE__ */ jsx4(
|
|
2356
|
+
"textarea",
|
|
2357
|
+
{
|
|
2358
|
+
className: "w-full rounded-md border p-2 text-xs font-medium resize-none focus:outline-none",
|
|
2359
|
+
style: {
|
|
2360
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #ffffff))",
|
|
2361
|
+
borderColor: "var(--papyrus-border-resolved, #d1d5db)",
|
|
2362
|
+
color: "var(--papyrus-text-resolved, #111827)"
|
|
2363
|
+
},
|
|
2364
|
+
placeholder: "Escreva seu comentario...",
|
|
2365
|
+
rows: 3,
|
|
2366
|
+
value: draftContent,
|
|
2367
|
+
onChange: (event) => setDraftContent(event.target.value),
|
|
2368
|
+
onKeyDown: (event) => {
|
|
2369
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
2370
|
+
event.preventDefault();
|
|
2371
|
+
handleSaveContent();
|
|
2372
|
+
}
|
|
2373
|
+
},
|
|
2374
|
+
autoFocus: true
|
|
2375
|
+
}
|
|
2376
|
+
),
|
|
2377
|
+
/* @__PURE__ */ jsx4("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ jsx4(
|
|
2378
|
+
"button",
|
|
2379
|
+
{
|
|
2380
|
+
type: "button",
|
|
2381
|
+
className: "rounded-md px-3 py-1.5 text-[11px] font-semibold text-white",
|
|
2382
|
+
style: { backgroundColor: accentColor },
|
|
2383
|
+
onClick: (event) => {
|
|
2384
|
+
event.stopPropagation();
|
|
2385
|
+
handleSaveContent();
|
|
2386
|
+
},
|
|
2387
|
+
children: (ann.content ?? "").trim() ? "Atualizar" : "Enviar"
|
|
2388
|
+
}
|
|
2389
|
+
) }),
|
|
2390
|
+
ann.replies && ann.replies.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "mt-3 space-y-2", children: ann.replies.map((reply) => /* @__PURE__ */ jsxs4(
|
|
2391
|
+
"div",
|
|
2392
|
+
{
|
|
2393
|
+
className: "rounded-md border p-2",
|
|
2394
|
+
style: {
|
|
2395
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #ffffff))",
|
|
2396
|
+
borderColor: "var(--papyrus-border-resolved, #d1d5db)"
|
|
2397
|
+
},
|
|
2398
|
+
children: [
|
|
2399
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs", children: reply.content }),
|
|
2400
|
+
/* @__PURE__ */ jsx4("p", { className: "mt-1 text-[10px] opacity-70", children: new Date(reply.createdAt).toLocaleTimeString([], {
|
|
2401
|
+
hour: "2-digit",
|
|
2402
|
+
minute: "2-digit"
|
|
2403
|
+
}) })
|
|
2404
|
+
]
|
|
2405
|
+
},
|
|
2406
|
+
reply.id
|
|
2407
|
+
)) }) : null,
|
|
2408
|
+
/* @__PURE__ */ jsxs4("div", { className: "mt-3 flex items-center gap-2", children: [
|
|
2409
|
+
/* @__PURE__ */ jsx4(
|
|
2410
|
+
"input",
|
|
2411
|
+
{
|
|
2412
|
+
type: "text",
|
|
2413
|
+
className: "flex-1 rounded-md border px-2 py-1.5 text-xs focus:outline-none",
|
|
2414
|
+
style: {
|
|
2415
|
+
background: "var(--papyrus-surface-resolved, var(--papyrus-surface, #ffffff))",
|
|
2416
|
+
borderColor: "var(--papyrus-border-resolved, #d1d5db)",
|
|
2417
|
+
color: "var(--papyrus-text-resolved, #111827)"
|
|
2418
|
+
},
|
|
2419
|
+
placeholder: "Responder...",
|
|
2420
|
+
value: draftReply,
|
|
2421
|
+
onChange: (event) => setDraftReply(event.target.value),
|
|
2422
|
+
onKeyDown: (event) => {
|
|
2423
|
+
if (event.key === "Enter") {
|
|
2424
|
+
event.preventDefault();
|
|
2425
|
+
handleReplySubmit();
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
),
|
|
2430
|
+
/* @__PURE__ */ jsx4(
|
|
2431
|
+
"button",
|
|
2432
|
+
{
|
|
2433
|
+
type: "button",
|
|
2434
|
+
className: "rounded-md px-3 py-1.5 text-[11px] font-semibold text-white",
|
|
2435
|
+
style: { backgroundColor: accentColor },
|
|
2436
|
+
onClick: handleReplySubmit,
|
|
2437
|
+
children: "Responder"
|
|
2438
|
+
}
|
|
2439
|
+
)
|
|
2440
|
+
] })
|
|
2441
|
+
]
|
|
2442
|
+
}
|
|
2443
|
+
),
|
|
2045
2444
|
isSelected && /* @__PURE__ */ jsx4(
|
|
2046
2445
|
"button",
|
|
2047
2446
|
{
|
|
@@ -2083,7 +2482,11 @@ var MIN_ZOOM = 0.2;
|
|
|
2083
2482
|
var MAX_ZOOM = 5;
|
|
2084
2483
|
var WIDTH_SNAP_PX = 4;
|
|
2085
2484
|
var WIDTH_HYSTERESIS_PX = 6;
|
|
2485
|
+
var MOBILE_HEADER_HIDE_DELTA_PX = 28;
|
|
2486
|
+
var MOBILE_HEADER_SHOW_DELTA_PX = 16;
|
|
2487
|
+
var MOBILE_HEADER_TOP_RESET_PX = 12;
|
|
2086
2488
|
var Viewer = ({ engine, style }) => {
|
|
2489
|
+
const viewerState = useViewerStore5();
|
|
2087
2490
|
const {
|
|
2088
2491
|
pageCount,
|
|
2089
2492
|
currentPage,
|
|
@@ -2096,7 +2499,8 @@ var Viewer = ({ engine, style }) => {
|
|
|
2096
2499
|
annotationColor,
|
|
2097
2500
|
setAnnotationColor,
|
|
2098
2501
|
toolDockOpen
|
|
2099
|
-
} =
|
|
2502
|
+
} = viewerState;
|
|
2503
|
+
const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
|
|
2100
2504
|
const isDark = uiTheme === "dark";
|
|
2101
2505
|
const viewerRef = useRef4(null);
|
|
2102
2506
|
const colorPickerRef = useRef4(null);
|
|
@@ -2106,6 +2510,11 @@ var Viewer = ({ engine, style }) => {
|
|
|
2106
2510
|
const jumpRef = useRef4(false);
|
|
2107
2511
|
const jumpTimerRef = useRef4(null);
|
|
2108
2512
|
const lastWidthRef = useRef4(null);
|
|
2513
|
+
const lastScrollTopRef = useRef4(0);
|
|
2514
|
+
const scrollDownAccumulatorRef = useRef4(0);
|
|
2515
|
+
const scrollUpAccumulatorRef = useRef4(0);
|
|
2516
|
+
const previousCurrentPageRef = useRef4(currentPage);
|
|
2517
|
+
const mobileTopbarVisibleRef = useRef4(mobileTopbarVisible);
|
|
2109
2518
|
const pinchRef = useRef4({
|
|
2110
2519
|
active: false,
|
|
2111
2520
|
startDistance: 0,
|
|
@@ -2118,6 +2527,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2118
2527
|
const [pageSizes, setPageSizes] = useState5({});
|
|
2119
2528
|
const [colorPickerOpen, setColorPickerOpen] = useState5(false);
|
|
2120
2529
|
const isCompact = availableWidth !== null && availableWidth < 820;
|
|
2530
|
+
const isMobileViewport = availableWidth !== null && availableWidth < 640;
|
|
2121
2531
|
const paddingY = isCompact ? "py-10" : "py-16";
|
|
2122
2532
|
const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
|
|
2123
2533
|
const colorPalette = [
|
|
@@ -2130,6 +2540,13 @@ var Viewer = ({ engine, style }) => {
|
|
|
2130
2540
|
"#8b5cf6",
|
|
2131
2541
|
"#111827"
|
|
2132
2542
|
];
|
|
2543
|
+
const setMobileTopbarVisibility = (visible) => {
|
|
2544
|
+
if (mobileTopbarVisibleRef.current === visible) return;
|
|
2545
|
+
mobileTopbarVisibleRef.current = visible;
|
|
2546
|
+
setDocumentState({
|
|
2547
|
+
mobileTopbarVisible: visible
|
|
2548
|
+
});
|
|
2549
|
+
};
|
|
2133
2550
|
useEffect4(() => {
|
|
2134
2551
|
if (!colorPickerOpen) return;
|
|
2135
2552
|
const handleClick = (event) => {
|
|
@@ -2144,6 +2561,9 @@ var Viewer = ({ engine, style }) => {
|
|
|
2144
2561
|
useEffect4(() => {
|
|
2145
2562
|
if (!toolDockOpen && colorPickerOpen) setColorPickerOpen(false);
|
|
2146
2563
|
}, [toolDockOpen, colorPickerOpen]);
|
|
2564
|
+
useEffect4(() => {
|
|
2565
|
+
mobileTopbarVisibleRef.current = mobileTopbarVisible;
|
|
2566
|
+
}, [mobileTopbarVisible]);
|
|
2147
2567
|
useEffect4(
|
|
2148
2568
|
() => () => {
|
|
2149
2569
|
if (pinchRef.current.rafId != null) {
|
|
@@ -2195,6 +2615,64 @@ var Viewer = ({ engine, style }) => {
|
|
|
2195
2615
|
observer.disconnect();
|
|
2196
2616
|
};
|
|
2197
2617
|
}, []);
|
|
2618
|
+
useEffect4(() => {
|
|
2619
|
+
const root = viewerRef.current;
|
|
2620
|
+
if (!root) return;
|
|
2621
|
+
if (!isMobileViewport) {
|
|
2622
|
+
lastScrollTopRef.current = root.scrollTop;
|
|
2623
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2624
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2625
|
+
setMobileTopbarVisibility(true);
|
|
2626
|
+
return;
|
|
2627
|
+
}
|
|
2628
|
+
lastScrollTopRef.current = root.scrollTop;
|
|
2629
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2630
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2631
|
+
const handleScroll = () => {
|
|
2632
|
+
const nextScrollTop = root.scrollTop;
|
|
2633
|
+
const delta = nextScrollTop - lastScrollTopRef.current;
|
|
2634
|
+
lastScrollTopRef.current = nextScrollTop;
|
|
2635
|
+
if (Math.abs(delta) < 1) return;
|
|
2636
|
+
if (nextScrollTop <= MOBILE_HEADER_TOP_RESET_PX) {
|
|
2637
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2638
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2639
|
+
setMobileTopbarVisibility(true);
|
|
2640
|
+
return;
|
|
2641
|
+
}
|
|
2642
|
+
if (delta > 0) {
|
|
2643
|
+
scrollDownAccumulatorRef.current += delta;
|
|
2644
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2645
|
+
} else {
|
|
2646
|
+
scrollUpAccumulatorRef.current += -delta;
|
|
2647
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2648
|
+
}
|
|
2649
|
+
if (scrollDownAccumulatorRef.current >= MOBILE_HEADER_HIDE_DELTA_PX && mobileTopbarVisibleRef.current) {
|
|
2650
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2651
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2652
|
+
setMobileTopbarVisibility(false);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
if (scrollUpAccumulatorRef.current >= MOBILE_HEADER_SHOW_DELTA_PX && !mobileTopbarVisibleRef.current) {
|
|
2656
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2657
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2658
|
+
setMobileTopbarVisibility(true);
|
|
2659
|
+
}
|
|
2660
|
+
};
|
|
2661
|
+
root.addEventListener("scroll", handleScroll, { passive: true });
|
|
2662
|
+
return () => {
|
|
2663
|
+
root.removeEventListener("scroll", handleScroll);
|
|
2664
|
+
};
|
|
2665
|
+
}, [isMobileViewport, setDocumentState]);
|
|
2666
|
+
useEffect4(() => {
|
|
2667
|
+
const previousPage = previousCurrentPageRef.current;
|
|
2668
|
+
previousCurrentPageRef.current = currentPage;
|
|
2669
|
+
if (!isMobileViewport) return;
|
|
2670
|
+
if (currentPage < previousPage && !mobileTopbarVisibleRef.current) {
|
|
2671
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2672
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2673
|
+
setMobileTopbarVisibility(true);
|
|
2674
|
+
}
|
|
2675
|
+
}, [currentPage, isMobileViewport, setDocumentState]);
|
|
2198
2676
|
useEffect4(() => {
|
|
2199
2677
|
let active = true;
|
|
2200
2678
|
if (!pageCount) return;
|
|
@@ -2309,7 +2787,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2309
2787
|
const virtualAnchor = currentPage - 1;
|
|
2310
2788
|
const virtualStart = Math.max(0, virtualAnchor - virtualOverscan);
|
|
2311
2789
|
const virtualEnd = Math.min(pageCount - 1, virtualAnchor + virtualOverscan);
|
|
2312
|
-
const fallbackSize =
|
|
2790
|
+
const fallbackSize = useMemo3(() => {
|
|
2313
2791
|
if (basePageSize && availableWidth) {
|
|
2314
2792
|
const fitScale = Math.min(
|
|
2315
2793
|
1,
|
|
@@ -2326,7 +2804,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2326
2804
|
height: Math.round(base * zoom)
|
|
2327
2805
|
};
|
|
2328
2806
|
}, [basePageSize, availableWidth, zoom]);
|
|
2329
|
-
const averagePageHeight =
|
|
2807
|
+
const averagePageHeight = useMemo3(() => {
|
|
2330
2808
|
const heights = Object.values(pageSizes).map((size) => size.height);
|
|
2331
2809
|
if (!heights.length)
|
|
2332
2810
|
return availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
|