@papyrus-sdk/ui-react 0.2.22 → 0.2.23
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/base.css +65 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +443 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +443 -41
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/LICENSE +0 -21
package/dist/index.js
CHANGED
|
@@ -72,6 +72,8 @@ var Topbar = ({
|
|
|
72
72
|
const [isMobileViewport, setIsMobileViewport] = (0, import_react.useState)(false);
|
|
73
73
|
const pageDigits = Math.max(2, String(pageCount || 1).length);
|
|
74
74
|
const isDark = uiTheme === "dark";
|
|
75
|
+
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
76
|
+
const isSingleViewportMode = renderTargetType === "element" || renderTargetType === "webview";
|
|
75
77
|
const canUseDOM = typeof document !== "undefined";
|
|
76
78
|
const hasMobileMenu = showZoomControls || showPageThemeSelector || showUIToggle || showUpload;
|
|
77
79
|
(0, import_react.useEffect)(() => {
|
|
@@ -153,6 +155,10 @@ var Topbar = ({
|
|
|
153
155
|
if (pageCount <= 0) return;
|
|
154
156
|
const nextPage = Math.max(1, Math.min(pageCount, isNaN(page) ? 1 : page));
|
|
155
157
|
engine.goToPage(nextPage);
|
|
158
|
+
if (isSingleViewportMode) {
|
|
159
|
+
setDocumentState({ currentPage: nextPage, scrollToPageSignal: null });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
156
162
|
triggerScrollToPage(nextPage - 1);
|
|
157
163
|
};
|
|
158
164
|
const handleFileUpload = async (event) => {
|
|
@@ -788,12 +794,20 @@ var withAlpha = (hex, alpha) => {
|
|
|
788
794
|
const b = parseInt(value.slice(4, 6), 16);
|
|
789
795
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
790
796
|
};
|
|
797
|
+
var isEpubDebugEnabled = () => {
|
|
798
|
+
try {
|
|
799
|
+
return Boolean(globalThis?.__PAPYRUS_EPUB_DEBUG__);
|
|
800
|
+
} catch {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
};
|
|
791
804
|
var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) => {
|
|
792
805
|
const wrapperRef = (0, import_react2.useRef)(null);
|
|
793
806
|
const canvasRef = (0, import_react2.useRef)(null);
|
|
794
807
|
const htmlRef = (0, import_react2.useRef)(null);
|
|
795
808
|
const accentSoft = withAlpha(accentColor, 0.12);
|
|
796
809
|
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
810
|
+
const isElementRender = renderTargetType === "element";
|
|
797
811
|
const [isVisible, setIsVisible] = (0, import_react2.useState)(false);
|
|
798
812
|
(0, import_react2.useEffect)(() => {
|
|
799
813
|
const target = wrapperRef.current;
|
|
@@ -818,14 +832,14 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
|
|
|
818
832
|
return () => observer.disconnect();
|
|
819
833
|
}, []);
|
|
820
834
|
(0, import_react2.useEffect)(() => {
|
|
821
|
-
if (
|
|
822
|
-
const target = canvasRef.current;
|
|
835
|
+
if (!isVisible || isElementRender) return;
|
|
836
|
+
const target = renderTargetType === "element" ? htmlRef.current : canvasRef.current;
|
|
823
837
|
if (target) {
|
|
824
838
|
engine.renderPage(pageIndex, target, 0.15).catch((err) => {
|
|
825
839
|
console.error("[Papyrus] Thumbnail render failed:", err);
|
|
826
840
|
});
|
|
827
841
|
}
|
|
828
|
-
}, [engine, pageIndex, renderTargetType, isVisible]);
|
|
842
|
+
}, [engine, pageIndex, renderTargetType, isVisible, isElementRender]);
|
|
829
843
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
830
844
|
"div",
|
|
831
845
|
{
|
|
@@ -839,13 +853,20 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
|
|
|
839
853
|
{
|
|
840
854
|
className: `shadow-lg rounded overflow-hidden mb-2 border ${isDark ? "border-[#333]" : "border-gray-200"}`,
|
|
841
855
|
children: [
|
|
856
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
857
|
+
"div",
|
|
858
|
+
{
|
|
859
|
+
className: `w-[90px] h-[120px] items-center justify-center text-[10px] font-black tracking-wider ${isElementRender ? "flex" : "hidden"} ${isDark ? "bg-[#1f1f1f] text-gray-300" : "bg-gray-100 text-gray-500"}`,
|
|
860
|
+
children: "CAP"
|
|
861
|
+
}
|
|
862
|
+
),
|
|
842
863
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
843
864
|
"canvas",
|
|
844
865
|
{
|
|
845
866
|
ref: canvasRef,
|
|
846
867
|
className: "max-w-full h-auto bg-white",
|
|
847
868
|
style: {
|
|
848
|
-
display:
|
|
869
|
+
display: isElementRender ? "none" : "block"
|
|
849
870
|
}
|
|
850
871
|
}
|
|
851
872
|
),
|
|
@@ -857,10 +878,9 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
|
|
|
857
878
|
style: {
|
|
858
879
|
width: 90,
|
|
859
880
|
height: 120,
|
|
860
|
-
display:
|
|
881
|
+
display: "none",
|
|
861
882
|
overflow: "hidden"
|
|
862
|
-
}
|
|
863
|
-
children: renderTargetType === "element" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full h-full flex items-center justify-center text-[10px] font-semibold text-gray-500", children: "HTML" })
|
|
883
|
+
}
|
|
864
884
|
}
|
|
865
885
|
)
|
|
866
886
|
]
|
|
@@ -879,9 +899,11 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
|
|
|
879
899
|
);
|
|
880
900
|
};
|
|
881
901
|
var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
|
|
882
|
-
const { triggerScrollToPage, outlineSearchQuery } = (0, import_core2.useViewerStore)();
|
|
902
|
+
const { triggerScrollToPage, outlineSearchQuery, setDocumentState } = (0, import_core2.useViewerStore)();
|
|
883
903
|
const [expanded, setExpanded] = (0, import_react2.useState)(true);
|
|
884
904
|
const accentSoft = withAlpha(accentColor, 0.2);
|
|
905
|
+
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
906
|
+
const isSingleViewportMode = renderTargetType === "element" || renderTargetType === "webview";
|
|
885
907
|
const matchesSearch = outlineSearchQuery === "" || item.title.toLowerCase().includes(outlineSearchQuery.toLowerCase());
|
|
886
908
|
const hasMatchingChildren = item.children?.some(
|
|
887
909
|
(child) => child.title.toLowerCase().includes(outlineSearchQuery.toLowerCase())
|
|
@@ -889,10 +911,53 @@ var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
|
|
|
889
911
|
if (!matchesSearch && !hasMatchingChildren && outlineSearchQuery !== "")
|
|
890
912
|
return null;
|
|
891
913
|
const handleClick = () => {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
914
|
+
void (async () => {
|
|
915
|
+
if (item.pageIndex < 0 && !item.dest) return;
|
|
916
|
+
let targetPageIndex = item.pageIndex;
|
|
917
|
+
let navigatedByDestination = false;
|
|
918
|
+
const destinationEngine = engine;
|
|
919
|
+
if (isSingleViewportMode && item.dest && typeof destinationEngine.goToDestination === "function") {
|
|
920
|
+
try {
|
|
921
|
+
if (isEpubDebugEnabled()) {
|
|
922
|
+
console.log("[EPUBUI] toc-click", {
|
|
923
|
+
title: item.title,
|
|
924
|
+
dest: item.dest,
|
|
925
|
+
pageIndex: item.pageIndex
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
const resolved = await destinationEngine.goToDestination(item.dest);
|
|
929
|
+
if (isEpubDebugEnabled()) {
|
|
930
|
+
console.log("[EPUBUI] toc-resolved", {
|
|
931
|
+
title: item.title,
|
|
932
|
+
resolved
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
if (resolved != null) targetPageIndex = resolved;
|
|
936
|
+
navigatedByDestination = true;
|
|
937
|
+
} catch {
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (item.dest && (!navigatedByDestination || targetPageIndex < 0)) {
|
|
941
|
+
try {
|
|
942
|
+
const resolved = await engine.getPageIndex(item.dest);
|
|
943
|
+
if (resolved != null) targetPageIndex = resolved;
|
|
944
|
+
} catch {
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
if (navigatedByDestination && isSingleViewportMode) {
|
|
948
|
+
const page2 = targetPageIndex >= 0 ? targetPageIndex + 1 : engine.getCurrentPage();
|
|
949
|
+
setDocumentState({ currentPage: page2, scrollToPageSignal: null });
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (targetPageIndex < 0) return;
|
|
953
|
+
const page = targetPageIndex + 1;
|
|
954
|
+
engine.goToPage(page);
|
|
955
|
+
if (isSingleViewportMode) {
|
|
956
|
+
setDocumentState({ currentPage: page, scrollToPageSignal: null });
|
|
957
|
+
} else {
|
|
958
|
+
triggerScrollToPage(targetPageIndex);
|
|
959
|
+
}
|
|
960
|
+
})();
|
|
896
961
|
};
|
|
897
962
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col", children: [
|
|
898
963
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
@@ -974,6 +1039,24 @@ var SidebarLeft = ({ engine, style }) => {
|
|
|
974
1039
|
accentColor
|
|
975
1040
|
} = (0, import_core2.useViewerStore)();
|
|
976
1041
|
const isDark = uiTheme === "dark";
|
|
1042
|
+
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
1043
|
+
const prefersSummaryByDefault = renderTargetType === "element" || renderTargetType === "webview";
|
|
1044
|
+
const autoSummaryKeyRef = (0, import_react2.useRef)(null);
|
|
1045
|
+
(0, import_react2.useEffect)(() => {
|
|
1046
|
+
if (!prefersSummaryByDefault) return;
|
|
1047
|
+
if (sidebarLeftTab !== "thumbnails") return;
|
|
1048
|
+
if (pageCount <= 0) return;
|
|
1049
|
+
const docKey = `${pageCount}:${outline.length}`;
|
|
1050
|
+
if (autoSummaryKeyRef.current === docKey) return;
|
|
1051
|
+
autoSummaryKeyRef.current = docKey;
|
|
1052
|
+
setSidebarLeftTab("summary");
|
|
1053
|
+
}, [
|
|
1054
|
+
prefersSummaryByDefault,
|
|
1055
|
+
sidebarLeftTab,
|
|
1056
|
+
pageCount,
|
|
1057
|
+
outline.length,
|
|
1058
|
+
setSidebarLeftTab
|
|
1059
|
+
]);
|
|
977
1060
|
if (!sidebarLeftOpen) return null;
|
|
978
1061
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
979
1062
|
"div",
|
|
@@ -1087,8 +1170,16 @@ var SidebarLeft = ({ engine, style }) => {
|
|
|
1087
1170
|
accentColor,
|
|
1088
1171
|
active: currentPage === idx + 1,
|
|
1089
1172
|
onClick: () => {
|
|
1090
|
-
|
|
1091
|
-
|
|
1173
|
+
const page = idx + 1;
|
|
1174
|
+
engine.goToPage(page);
|
|
1175
|
+
if (prefersSummaryByDefault) {
|
|
1176
|
+
setDocumentState({
|
|
1177
|
+
currentPage: page,
|
|
1178
|
+
scrollToPageSignal: null
|
|
1179
|
+
});
|
|
1180
|
+
} else {
|
|
1181
|
+
triggerScrollToPage(idx);
|
|
1182
|
+
}
|
|
1092
1183
|
}
|
|
1093
1184
|
},
|
|
1094
1185
|
idx
|
|
@@ -1140,10 +1231,14 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1140
1231
|
} = (0, import_core3.useViewerStore)();
|
|
1141
1232
|
const [query, setQuery] = (0, import_react3.useState)("");
|
|
1142
1233
|
const [isSearching, setIsSearching] = (0, import_react3.useState)(false);
|
|
1143
|
-
const [contentDrafts, setContentDrafts] = (0, import_react3.useState)(
|
|
1234
|
+
const [contentDrafts, setContentDrafts] = (0, import_react3.useState)(
|
|
1235
|
+
{}
|
|
1236
|
+
);
|
|
1144
1237
|
const [replyDrafts, setReplyDrafts] = (0, import_react3.useState)({});
|
|
1145
1238
|
const searchService = new import_core3.SearchService(engine);
|
|
1146
1239
|
const isDark = uiTheme === "dark";
|
|
1240
|
+
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
1241
|
+
const isSingleViewportMode = renderTargetType === "element" || renderTargetType === "webview";
|
|
1147
1242
|
const accentSoft = withAlpha2(accentColor, 0.12);
|
|
1148
1243
|
const resultsCount = searchResults.length;
|
|
1149
1244
|
const handleSearch = async (e) => {
|
|
@@ -1160,9 +1255,13 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1160
1255
|
const jumpToAnnotation = (annotation) => {
|
|
1161
1256
|
const page = annotation.pageIndex + 1;
|
|
1162
1257
|
engine.goToPage(page);
|
|
1163
|
-
|
|
1258
|
+
if (isSingleViewportMode) {
|
|
1259
|
+
setDocumentState({ currentPage: page, scrollToPageSignal: null });
|
|
1260
|
+
} else {
|
|
1261
|
+
setDocumentState({ currentPage: page });
|
|
1262
|
+
triggerScrollToPage(annotation.pageIndex);
|
|
1263
|
+
}
|
|
1164
1264
|
setSelectedAnnotation(annotation.id);
|
|
1165
|
-
triggerScrollToPage(annotation.pageIndex);
|
|
1166
1265
|
};
|
|
1167
1266
|
const getContentDraft = (annotation) => {
|
|
1168
1267
|
if (Object.prototype.hasOwnProperty.call(contentDrafts, annotation.id)) {
|
|
@@ -1309,11 +1408,19 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1309
1408
|
onClick: () => {
|
|
1310
1409
|
const page = res.pageIndex + 1;
|
|
1311
1410
|
engine.goToPage(page);
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1411
|
+
if (isSingleViewportMode) {
|
|
1412
|
+
setDocumentState({
|
|
1413
|
+
activeSearchIndex: idx,
|
|
1414
|
+
currentPage: page,
|
|
1415
|
+
scrollToPageSignal: null
|
|
1416
|
+
});
|
|
1417
|
+
} else {
|
|
1418
|
+
setDocumentState({
|
|
1419
|
+
activeSearchIndex: idx,
|
|
1420
|
+
currentPage: page
|
|
1421
|
+
});
|
|
1422
|
+
triggerScrollToPage(res.pageIndex);
|
|
1423
|
+
}
|
|
1317
1424
|
},
|
|
1318
1425
|
className: `p-4 rounded-xl border-2 cursor-pointer transition-all group hover:scale-[1.02] ${idx === activeSearchIndex ? "shadow-lg" : isDark ? "border-[#333] hover:border-[#555] bg-[#222]" : "border-gray-50 hover:border-gray-200 bg-gray-50/50 hover:bg-white"}`,
|
|
1319
1426
|
style: idx === activeSearchIndex ? {
|
|
@@ -1400,7 +1507,9 @@ var SidebarRight = ({ engine, style }) => {
|
|
|
1400
1507
|
const replies = ann.replies ?? [];
|
|
1401
1508
|
const contentDraft = getContentDraft(ann);
|
|
1402
1509
|
const replyDraft = getReplyDraft(ann.id);
|
|
1403
|
-
const hasExistingContent = Boolean(
|
|
1510
|
+
const hasExistingContent = Boolean(
|
|
1511
|
+
(ann.content ?? "").trim()
|
|
1512
|
+
);
|
|
1404
1513
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1405
1514
|
"div",
|
|
1406
1515
|
{
|
|
@@ -1560,6 +1669,7 @@ var PageRenderer = ({
|
|
|
1560
1669
|
engine,
|
|
1561
1670
|
pageIndex,
|
|
1562
1671
|
availableWidth,
|
|
1672
|
+
availableHeight,
|
|
1563
1673
|
onMeasuredSize
|
|
1564
1674
|
}) => {
|
|
1565
1675
|
const containerRef = (0, import_react4.useRef)(null);
|
|
@@ -1601,6 +1711,11 @@ var PageRenderer = ({
|
|
|
1601
1711
|
} = (0, import_core4.useViewerStore)();
|
|
1602
1712
|
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
1603
1713
|
const isElementRender = renderTargetType === "element";
|
|
1714
|
+
const isLandscape = typeof availableWidth === "number" && typeof availableHeight === "number" && availableWidth > availableHeight;
|
|
1715
|
+
const isLandscapeShort = isLandscape && typeof availableHeight === "number" && availableHeight <= 500;
|
|
1716
|
+
const isMobileElementViewport = isElementRender && typeof availableWidth === "number" && (availableWidth <= 768 || isLandscapeShort);
|
|
1717
|
+
const renderZoomDependency = isElementRender ? 1 : zoom;
|
|
1718
|
+
const renderRotationDependency = isElementRender ? 0 : rotation;
|
|
1604
1719
|
const textMarkupTools = /* @__PURE__ */ new Set([
|
|
1605
1720
|
"highlight",
|
|
1606
1721
|
"underline",
|
|
@@ -1630,6 +1745,10 @@ var PageRenderer = ({
|
|
|
1630
1745
|
},
|
|
1631
1746
|
[]
|
|
1632
1747
|
);
|
|
1748
|
+
(0, import_react4.useEffect)(() => {
|
|
1749
|
+
if (!isElementRender) return;
|
|
1750
|
+
setPageSize(null);
|
|
1751
|
+
}, [isElementRender, pageIndex]);
|
|
1633
1752
|
(0, import_react4.useEffect)(() => {
|
|
1634
1753
|
let active = true;
|
|
1635
1754
|
const loadSize = async () => {
|
|
@@ -1648,12 +1767,13 @@ var PageRenderer = ({
|
|
|
1648
1767
|
};
|
|
1649
1768
|
}, [engine, pageIndex]);
|
|
1650
1769
|
const fitScale = (0, import_react4.useMemo)(() => {
|
|
1770
|
+
if (isElementRender && isMobileElementViewport) return 1;
|
|
1651
1771
|
if (!availableWidth || !pageSize?.width) return 1;
|
|
1652
1772
|
const targetWidth = Math.max(0, availableWidth - 48);
|
|
1653
1773
|
if (!targetWidth) return 1;
|
|
1654
1774
|
const rawScale = Math.min(1, targetWidth / pageSize.width);
|
|
1655
1775
|
return Math.round(rawScale * SCALE_PRECISION) / SCALE_PRECISION;
|
|
1656
|
-
}, [availableWidth, pageSize]);
|
|
1776
|
+
}, [isElementRender, isMobileElementViewport, availableWidth, pageSize]);
|
|
1657
1777
|
const displaySize = (0, import_react4.useMemo)(() => {
|
|
1658
1778
|
if (!pageSize) return null;
|
|
1659
1779
|
const scale = zoom * fitScale;
|
|
@@ -1689,6 +1809,15 @@ var PageRenderer = ({
|
|
|
1689
1809
|
canvasRef.current.style.height = `${displaySize.height}px`;
|
|
1690
1810
|
}
|
|
1691
1811
|
await engine.renderPage(pageIndex, renderTarget, canvasRenderScale);
|
|
1812
|
+
const measuredSize = await engine.getPageDimensions(pageIndex);
|
|
1813
|
+
if (measuredSize.width > 0 && measuredSize.height > 0 && active) {
|
|
1814
|
+
setPageSize((prev) => {
|
|
1815
|
+
if (prev && prev.width === measuredSize.width && prev.height === measuredSize.height) {
|
|
1816
|
+
return prev;
|
|
1817
|
+
}
|
|
1818
|
+
return measuredSize;
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1692
1821
|
if (!isElementRender && !pageSize && canvasRef.current) {
|
|
1693
1822
|
const denom = canvasRenderScale * Math.max(zoom, 0.01);
|
|
1694
1823
|
if (denom > 0) {
|
|
@@ -1731,13 +1860,24 @@ var PageRenderer = ({
|
|
|
1731
1860
|
}, [
|
|
1732
1861
|
engine,
|
|
1733
1862
|
pageIndex,
|
|
1734
|
-
zoom,
|
|
1735
|
-
rotation,
|
|
1736
1863
|
isElementRender,
|
|
1864
|
+
availableWidth,
|
|
1737
1865
|
fitScale,
|
|
1738
1866
|
displaySize,
|
|
1739
|
-
pageSize
|
|
1867
|
+
pageSize,
|
|
1868
|
+
renderZoomDependency,
|
|
1869
|
+
renderRotationDependency
|
|
1740
1870
|
]);
|
|
1871
|
+
(0, import_react4.useEffect)(() => {
|
|
1872
|
+
if (!isElementRender || pageSize) return;
|
|
1873
|
+
const target = htmlLayerRef.current;
|
|
1874
|
+
if (!target) return;
|
|
1875
|
+
const measuredWidth = target.clientWidth || target.scrollWidth || 0;
|
|
1876
|
+
const measuredHeight = target.clientHeight || target.scrollHeight || 0;
|
|
1877
|
+
if (measuredWidth > 0 && measuredHeight > 0) {
|
|
1878
|
+
setPageSize({ width: measuredWidth, height: measuredHeight });
|
|
1879
|
+
}
|
|
1880
|
+
}, [isElementRender, pageSize, textLayerVersion]);
|
|
1741
1881
|
(0, import_react4.useEffect)(() => {
|
|
1742
1882
|
if (isElementRender) return;
|
|
1743
1883
|
const layer = textLayerRef.current;
|
|
@@ -2062,14 +2202,26 @@ var PageRenderer = ({
|
|
|
2062
2202
|
return "none";
|
|
2063
2203
|
}
|
|
2064
2204
|
};
|
|
2205
|
+
const elementScale = zoom * fitScale;
|
|
2206
|
+
const elementBaseWidth = isElementRender ? isMobileElementViewport && availableWidth != null ? Math.max(260, Math.round(availableWidth)) : pageSize?.width ?? 640 : pageSize?.width ?? 640;
|
|
2207
|
+
const elementBaseHeight = pageSize?.height ?? (isElementRender ? 700 : 900);
|
|
2208
|
+
const elementContainerStyle = isElementRender ? {
|
|
2209
|
+
width: `${Math.max(1, Math.round(elementBaseWidth * elementScale))}px`,
|
|
2210
|
+
height: `${Math.max(
|
|
2211
|
+
1,
|
|
2212
|
+
Math.round(elementBaseHeight * elementScale)
|
|
2213
|
+
)}px`
|
|
2214
|
+
} : void 0;
|
|
2065
2215
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2066
2216
|
"div",
|
|
2067
2217
|
{
|
|
2068
2218
|
ref: containerRef,
|
|
2069
|
-
className: `relative inline-block shadow-2xl bg-white mb-10 ${canSelectText ? "" : "no-select cursor-crosshair"}`,
|
|
2219
|
+
className: `relative inline-block shadow-2xl bg-white ${isMobileElementViewport ? "mb-0" : "mb-10"} ${canSelectText ? "" : "no-select cursor-crosshair"}`,
|
|
2070
2220
|
style: {
|
|
2071
2221
|
scrollMarginTop: "20px",
|
|
2072
2222
|
minHeight: "100px",
|
|
2223
|
+
overflow: "hidden",
|
|
2224
|
+
...elementContainerStyle,
|
|
2073
2225
|
touchAction: activeTool === "ink" || activeTool === "text" || activeTool === "comment" ? "none" : "auto"
|
|
2074
2226
|
},
|
|
2075
2227
|
onMouseDown: handleMouseDown,
|
|
@@ -2099,7 +2251,11 @@ var PageRenderer = ({
|
|
|
2099
2251
|
className: "block",
|
|
2100
2252
|
style: {
|
|
2101
2253
|
filter: getPageFilter(),
|
|
2102
|
-
display: isElementRender ? "block" : "none"
|
|
2254
|
+
display: isElementRender ? "block" : "none",
|
|
2255
|
+
width: `${elementBaseWidth}px`,
|
|
2256
|
+
height: `${elementBaseHeight}px`,
|
|
2257
|
+
transform: `scale(${elementScale})`,
|
|
2258
|
+
transformOrigin: "top left"
|
|
2103
2259
|
}
|
|
2104
2260
|
}
|
|
2105
2261
|
),
|
|
@@ -2549,6 +2705,15 @@ var PageRenderer_default = PageRenderer;
|
|
|
2549
2705
|
|
|
2550
2706
|
// components/Viewer.tsx
|
|
2551
2707
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2708
|
+
var withAlpha3 = (hex, alpha) => {
|
|
2709
|
+
const normalized = hex.replace("#", "").trim();
|
|
2710
|
+
const value = normalized.length === 3 ? normalized.split("").map((c) => c + c).join("") : normalized;
|
|
2711
|
+
if (value.length !== 6) return hex;
|
|
2712
|
+
const r = parseInt(value.slice(0, 2), 16);
|
|
2713
|
+
const g = parseInt(value.slice(2, 4), 16);
|
|
2714
|
+
const b = parseInt(value.slice(4, 6), 16);
|
|
2715
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
2716
|
+
};
|
|
2552
2717
|
var BASE_OVERSCAN = 6;
|
|
2553
2718
|
var MIN_ZOOM = 0.2;
|
|
2554
2719
|
var MAX_ZOOM = 5;
|
|
@@ -2570,6 +2735,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2570
2735
|
uiTheme,
|
|
2571
2736
|
scrollToPageSignal,
|
|
2572
2737
|
setDocumentState,
|
|
2738
|
+
triggerScrollToPage,
|
|
2573
2739
|
accentColor,
|
|
2574
2740
|
annotationColor,
|
|
2575
2741
|
setAnnotationColor,
|
|
@@ -2577,7 +2743,10 @@ var Viewer = ({ engine, style }) => {
|
|
|
2577
2743
|
} = viewerState;
|
|
2578
2744
|
const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
|
|
2579
2745
|
const isDark = uiTheme === "dark";
|
|
2746
|
+
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
2747
|
+
const isSingleViewportMode = renderTargetType === "element" || renderTargetType === "webview";
|
|
2580
2748
|
const viewerRef = (0, import_react5.useRef)(null);
|
|
2749
|
+
const singleNavInFlightRef = (0, import_react5.useRef)(false);
|
|
2581
2750
|
const colorPickerRef = (0, import_react5.useRef)(null);
|
|
2582
2751
|
const pageRefs = (0, import_react5.useRef)([]);
|
|
2583
2752
|
const intersectionRatiosRef = (0, import_react5.useRef)({});
|
|
@@ -2600,6 +2769,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2600
2769
|
});
|
|
2601
2770
|
const [availableWidth, setAvailableWidth] = (0, import_react5.useState)(null);
|
|
2602
2771
|
const [availableHeight, setAvailableHeight] = (0, import_react5.useState)(null);
|
|
2772
|
+
const [viewerBounds, setViewerBounds] = (0, import_react5.useState)(null);
|
|
2603
2773
|
const [basePageSize, setBasePageSize] = (0, import_react5.useState)(null);
|
|
2604
2774
|
const [pageSizes, setPageSizes] = (0, import_react5.useState)({});
|
|
2605
2775
|
const [colorPickerOpen, setColorPickerOpen] = (0, import_react5.useState)(false);
|
|
@@ -2607,7 +2777,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2607
2777
|
const isLandscapeShort = isLandscape && availableHeight !== null && availableHeight <= MOBILE_LANDSCAPE_MAX_HEIGHT_PX2;
|
|
2608
2778
|
const isCompact = availableWidth !== null && (availableWidth < 820 || isLandscapeShort);
|
|
2609
2779
|
const isMobileViewport = availableWidth !== null && (availableWidth < 640 || isLandscapeShort);
|
|
2610
|
-
const paddingY = isCompact ? "py-10" : "py-16";
|
|
2780
|
+
const paddingY = isSingleViewportMode && isMobileViewport ? "py-0" : isCompact ? "py-10" : "py-16";
|
|
2611
2781
|
const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
|
|
2612
2782
|
const colorPalette = [
|
|
2613
2783
|
"#fbbf24",
|
|
@@ -2619,6 +2789,45 @@ var Viewer = ({ engine, style }) => {
|
|
|
2619
2789
|
"#8b5cf6",
|
|
2620
2790
|
"#111827"
|
|
2621
2791
|
];
|
|
2792
|
+
const destinationNavEngine = engine;
|
|
2793
|
+
const canUseDestinationNavigation = isSingleViewportMode && typeof destinationNavEngine.goToAdjacentDestination === "function";
|
|
2794
|
+
const destinationNavigationState = isSingleViewportMode && typeof destinationNavEngine.getDestinationNavigationState === "function" ? destinationNavEngine.getDestinationNavigationState() : null;
|
|
2795
|
+
const canGoPrev = destinationNavigationState?.hasPrev ?? currentPage > 1;
|
|
2796
|
+
const canGoNext = destinationNavigationState?.hasNext ?? currentPage < pageCount;
|
|
2797
|
+
const viewerOverflowClass = isSingleViewportMode ? "overflow-hidden" : "overflow-y-scroll overflow-x-hidden";
|
|
2798
|
+
const navigateBy = (delta) => {
|
|
2799
|
+
if (pageCount <= 0) return;
|
|
2800
|
+
if (canUseDestinationNavigation) {
|
|
2801
|
+
if (singleNavInFlightRef.current) return;
|
|
2802
|
+
singleNavInFlightRef.current = true;
|
|
2803
|
+
void (async () => {
|
|
2804
|
+
try {
|
|
2805
|
+
const resolved = await destinationNavEngine.goToAdjacentDestination(
|
|
2806
|
+
delta
|
|
2807
|
+
);
|
|
2808
|
+
if (resolved == null) return;
|
|
2809
|
+
setDocumentState({
|
|
2810
|
+
currentPage: resolved + 1,
|
|
2811
|
+
scrollToPageSignal: null
|
|
2812
|
+
});
|
|
2813
|
+
} finally {
|
|
2814
|
+
singleNavInFlightRef.current = false;
|
|
2815
|
+
}
|
|
2816
|
+
})();
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
const enginePage = Number(engine.getCurrentPage?.());
|
|
2820
|
+
const normalizedEnginePage = Number.isFinite(enginePage) && enginePage >= 1 ? Math.floor(enginePage) : null;
|
|
2821
|
+
const basePage = normalizedEnginePage != null && Math.abs(normalizedEnginePage - currentPage) <= 1 ? normalizedEnginePage : currentPage;
|
|
2822
|
+
const clampedPage = Math.max(1, Math.min(pageCount, basePage + delta));
|
|
2823
|
+
if (clampedPage === basePage) return;
|
|
2824
|
+
engine.goToPage(clampedPage);
|
|
2825
|
+
if (isSingleViewportMode) {
|
|
2826
|
+
setDocumentState({ currentPage: clampedPage, scrollToPageSignal: null });
|
|
2827
|
+
return;
|
|
2828
|
+
}
|
|
2829
|
+
triggerScrollToPage(clampedPage - 1);
|
|
2830
|
+
};
|
|
2622
2831
|
const setMobileTopbarVisibility = (visible) => {
|
|
2623
2832
|
if (mobileTopbarVisibleRef.current === visible) return;
|
|
2624
2833
|
mobileTopbarVisibleRef.current = visible;
|
|
@@ -2705,10 +2914,48 @@ var Viewer = ({ engine, style }) => {
|
|
|
2705
2914
|
observer.disconnect();
|
|
2706
2915
|
};
|
|
2707
2916
|
}, []);
|
|
2917
|
+
(0, import_react5.useEffect)(() => {
|
|
2918
|
+
if (!isSingleViewportMode) return;
|
|
2919
|
+
const viewerElement = viewerRef.current;
|
|
2920
|
+
if (!viewerElement) return;
|
|
2921
|
+
let rafId = null;
|
|
2922
|
+
const updateBounds = () => {
|
|
2923
|
+
const rect = viewerElement.getBoundingClientRect();
|
|
2924
|
+
setViewerBounds({
|
|
2925
|
+
left: rect.left,
|
|
2926
|
+
width: rect.width,
|
|
2927
|
+
top: rect.top,
|
|
2928
|
+
height: rect.height
|
|
2929
|
+
});
|
|
2930
|
+
};
|
|
2931
|
+
const scheduleUpdate = () => {
|
|
2932
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
2933
|
+
rafId = requestAnimationFrame(() => {
|
|
2934
|
+
rafId = null;
|
|
2935
|
+
updateBounds();
|
|
2936
|
+
});
|
|
2937
|
+
};
|
|
2938
|
+
updateBounds();
|
|
2939
|
+
viewerElement.addEventListener("scroll", scheduleUpdate, { passive: true });
|
|
2940
|
+
window.addEventListener("resize", scheduleUpdate);
|
|
2941
|
+
window.addEventListener("scroll", scheduleUpdate, { passive: true });
|
|
2942
|
+
let observer = null;
|
|
2943
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
2944
|
+
observer = new ResizeObserver(() => scheduleUpdate());
|
|
2945
|
+
observer.observe(viewerElement);
|
|
2946
|
+
}
|
|
2947
|
+
return () => {
|
|
2948
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
2949
|
+
viewerElement.removeEventListener("scroll", scheduleUpdate);
|
|
2950
|
+
window.removeEventListener("resize", scheduleUpdate);
|
|
2951
|
+
window.removeEventListener("scroll", scheduleUpdate);
|
|
2952
|
+
observer?.disconnect();
|
|
2953
|
+
};
|
|
2954
|
+
}, [isSingleViewportMode]);
|
|
2708
2955
|
(0, import_react5.useEffect)(() => {
|
|
2709
2956
|
const root = viewerRef.current;
|
|
2710
2957
|
if (!root) return;
|
|
2711
|
-
if (!isMobileViewport) {
|
|
2958
|
+
if (isSingleViewportMode || !isMobileViewport) {
|
|
2712
2959
|
lastScrollTopRef.current = root.scrollTop;
|
|
2713
2960
|
scrollDownAccumulatorRef.current = 0;
|
|
2714
2961
|
scrollUpAccumulatorRef.current = 0;
|
|
@@ -2752,7 +2999,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2752
2999
|
return () => {
|
|
2753
3000
|
root.removeEventListener("scroll", handleScroll);
|
|
2754
3001
|
};
|
|
2755
|
-
}, [isMobileViewport, setDocumentState]);
|
|
3002
|
+
}, [isSingleViewportMode, isMobileViewport, setDocumentState]);
|
|
2756
3003
|
(0, import_react5.useEffect)(() => {
|
|
2757
3004
|
const previousPage = previousCurrentPageRef.current;
|
|
2758
3005
|
previousCurrentPageRef.current = currentPage;
|
|
@@ -2781,6 +3028,19 @@ var Viewer = ({ engine, style }) => {
|
|
|
2781
3028
|
}, [engine, pageCount]);
|
|
2782
3029
|
(0, import_react5.useEffect)(() => {
|
|
2783
3030
|
if (scrollToPageSignal == null) return;
|
|
3031
|
+
if (isSingleViewportMode) {
|
|
3032
|
+
const nextPageIndex = Math.max(
|
|
3033
|
+
0,
|
|
3034
|
+
Math.min(Math.max(pageCount - 1, 0), scrollToPageSignal)
|
|
3035
|
+
);
|
|
3036
|
+
const root2 = viewerRef.current;
|
|
3037
|
+
if (root2) root2.scrollTop = 0;
|
|
3038
|
+
setDocumentState({
|
|
3039
|
+
currentPage: nextPageIndex + 1,
|
|
3040
|
+
scrollToPageSignal: null
|
|
3041
|
+
});
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
2784
3044
|
const root = viewerRef.current;
|
|
2785
3045
|
const target = pageRefs.current[scrollToPageSignal];
|
|
2786
3046
|
if (root) {
|
|
@@ -2817,16 +3077,57 @@ var Viewer = ({ engine, style }) => {
|
|
|
2817
3077
|
setDocumentState({ scrollToPageSignal: null });
|
|
2818
3078
|
}, [
|
|
2819
3079
|
scrollToPageSignal,
|
|
3080
|
+
isSingleViewportMode,
|
|
2820
3081
|
setDocumentState,
|
|
2821
3082
|
basePageSize,
|
|
2822
3083
|
availableWidth,
|
|
2823
3084
|
zoom,
|
|
2824
3085
|
pageCount
|
|
2825
3086
|
]);
|
|
3087
|
+
(0, import_react5.useEffect)(() => {
|
|
3088
|
+
if (!isSingleViewportMode) return;
|
|
3089
|
+
const root = viewerRef.current;
|
|
3090
|
+
if (!root) return;
|
|
3091
|
+
root.scrollTop = 0;
|
|
3092
|
+
}, [isSingleViewportMode, currentPage]);
|
|
2826
3093
|
(0, import_react5.useEffect)(() => {
|
|
2827
3094
|
setPageSizes({});
|
|
2828
3095
|
}, [zoom]);
|
|
2829
3096
|
(0, import_react5.useEffect)(() => {
|
|
3097
|
+
if (pageCount <= 1) return;
|
|
3098
|
+
const handleKeyNavigation = (event) => {
|
|
3099
|
+
if (event.defaultPrevented) return;
|
|
3100
|
+
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
|
3101
|
+
const target = event.target;
|
|
3102
|
+
if (target) {
|
|
3103
|
+
const tag = target.tagName;
|
|
3104
|
+
const isEditable = tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable || target.getAttribute("contenteditable") === "true";
|
|
3105
|
+
if (isEditable) return;
|
|
3106
|
+
}
|
|
3107
|
+
if (event.key === "ArrowLeft") {
|
|
3108
|
+
event.preventDefault();
|
|
3109
|
+
if (!canGoPrev) return;
|
|
3110
|
+
navigateBy(-1);
|
|
3111
|
+
return;
|
|
3112
|
+
}
|
|
3113
|
+
if (event.key === "ArrowRight") {
|
|
3114
|
+
event.preventDefault();
|
|
3115
|
+
if (!canGoNext) return;
|
|
3116
|
+
navigateBy(1);
|
|
3117
|
+
}
|
|
3118
|
+
};
|
|
3119
|
+
window.addEventListener("keydown", handleKeyNavigation);
|
|
3120
|
+
return () => window.removeEventListener("keydown", handleKeyNavigation);
|
|
3121
|
+
}, [
|
|
3122
|
+
currentPage,
|
|
3123
|
+
pageCount,
|
|
3124
|
+
triggerScrollToPage,
|
|
3125
|
+
engine,
|
|
3126
|
+
canGoPrev,
|
|
3127
|
+
canGoNext
|
|
3128
|
+
]);
|
|
3129
|
+
(0, import_react5.useEffect)(() => {
|
|
3130
|
+
if (isSingleViewportMode) return;
|
|
2830
3131
|
const root = viewerRef.current;
|
|
2831
3132
|
if (!root) return;
|
|
2832
3133
|
const flushCurrentPage = () => {
|
|
@@ -2872,11 +3173,15 @@ var Viewer = ({ engine, style }) => {
|
|
|
2872
3173
|
pageElements.forEach((el) => observer.unobserve(el));
|
|
2873
3174
|
observer.disconnect();
|
|
2874
3175
|
};
|
|
2875
|
-
}, [pageCount, setDocumentState, currentPage]);
|
|
3176
|
+
}, [pageCount, setDocumentState, currentPage, isSingleViewportMode]);
|
|
3177
|
+
const safeCurrentPageIndex = Math.max(
|
|
3178
|
+
0,
|
|
3179
|
+
Math.min(Math.max(pageCount - 1, 0), currentPage - 1)
|
|
3180
|
+
);
|
|
2876
3181
|
const virtualOverscan = zoom > 1.35 ? 4 : BASE_OVERSCAN;
|
|
2877
|
-
const virtualAnchor =
|
|
2878
|
-
const virtualStart = Math.max(0, virtualAnchor - virtualOverscan);
|
|
2879
|
-
const virtualEnd = Math.min(pageCount - 1, virtualAnchor + virtualOverscan);
|
|
3182
|
+
const virtualAnchor = safeCurrentPageIndex;
|
|
3183
|
+
const virtualStart = isSingleViewportMode ? safeCurrentPageIndex : Math.max(0, virtualAnchor - virtualOverscan);
|
|
3184
|
+
const virtualEnd = isSingleViewportMode ? safeCurrentPageIndex : Math.min(pageCount - 1, virtualAnchor + virtualOverscan);
|
|
2880
3185
|
const fallbackSize = (0, import_react5.useMemo)(() => {
|
|
2881
3186
|
if (basePageSize && availableWidth) {
|
|
2882
3187
|
const fitScale = Math.min(
|
|
@@ -2900,7 +3205,17 @@ var Viewer = ({ engine, style }) => {
|
|
|
2900
3205
|
return availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
|
|
2901
3206
|
return Math.round(heights.reduce((sum, h) => sum + h, 0) / heights.length);
|
|
2902
3207
|
}, [pageSizes, availableWidth]);
|
|
2903
|
-
const pages = Array.from({ length: pageCount }).map((_, i) => i);
|
|
3208
|
+
const pages = isSingleViewportMode ? pageCount > 0 ? [safeCurrentPageIndex] : [] : Array.from({ length: pageCount }).map((_, i) => i);
|
|
3209
|
+
const viewerStyle = (0, import_react5.useMemo)(
|
|
3210
|
+
() => isSingleViewportMode ? {
|
|
3211
|
+
...style ?? {},
|
|
3212
|
+
overflow: "hidden",
|
|
3213
|
+
overflowY: "hidden",
|
|
3214
|
+
overflowX: "hidden",
|
|
3215
|
+
overscrollBehavior: "none"
|
|
3216
|
+
} : style ?? {},
|
|
3217
|
+
[isSingleViewportMode, style]
|
|
3218
|
+
);
|
|
2904
3219
|
const handlePageMeasured = (pageIndex, size) => {
|
|
2905
3220
|
setPageSizes((prev) => {
|
|
2906
3221
|
const current = prev[pageIndex];
|
|
@@ -2993,8 +3308,8 @@ var Viewer = ({ engine, style }) => {
|
|
|
2993
3308
|
onTouchMove: handleTouchMove,
|
|
2994
3309
|
onTouchEnd: handleTouchEnd,
|
|
2995
3310
|
onTouchCancel: handleTouchEnd,
|
|
2996
|
-
className: `papyrus-viewer papyrus-theme min-w-0 w-full flex-1
|
|
2997
|
-
style,
|
|
3311
|
+
className: `papyrus-viewer papyrus-theme min-h-0 min-w-0 w-full flex-1 ${viewerOverflowClass} flex flex-col items-center ${paddingY} relative custom-scrollbar scroll-smooth ${isDark ? "bg-[#121212]" : "bg-[#e9ecef]"}`,
|
|
3312
|
+
style: viewerStyle,
|
|
2998
3313
|
children: [
|
|
2999
3314
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex flex-col items-center gap-6 w-full min-w-0", children: pages.map((idx) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3000
3315
|
"div",
|
|
@@ -3003,13 +3318,14 @@ var Viewer = ({ engine, style }) => {
|
|
|
3003
3318
|
pageRefs.current[idx] = element;
|
|
3004
3319
|
},
|
|
3005
3320
|
"data-page-index": idx,
|
|
3006
|
-
className:
|
|
3321
|
+
className: `page-container ${isSingleViewportMode ? "relative" : ""}`,
|
|
3007
3322
|
children: idx >= virtualStart && idx <= virtualEnd ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3008
3323
|
PageRenderer_default,
|
|
3009
3324
|
{
|
|
3010
3325
|
engine,
|
|
3011
3326
|
pageIndex: idx,
|
|
3012
3327
|
availableWidth: availableWidth ?? void 0,
|
|
3328
|
+
availableHeight: availableHeight ?? void 0,
|
|
3013
3329
|
onMeasuredSize: handlePageMeasured
|
|
3014
3330
|
}
|
|
3015
3331
|
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
@@ -3023,8 +3339,94 @@ var Viewer = ({ engine, style }) => {
|
|
|
3023
3339
|
}
|
|
3024
3340
|
)
|
|
3025
3341
|
},
|
|
3026
|
-
idx
|
|
3342
|
+
isSingleViewportMode ? "single-viewport" : idx
|
|
3027
3343
|
)) }),
|
|
3344
|
+
isSingleViewportMode && pageCount > 1 && viewerBounds && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3345
|
+
"div",
|
|
3346
|
+
{
|
|
3347
|
+
className: "pointer-events-none fixed z-[75] flex items-center justify-between px-1.5 sm:px-2.5",
|
|
3348
|
+
style: {
|
|
3349
|
+
left: viewerBounds.left,
|
|
3350
|
+
width: viewerBounds.width,
|
|
3351
|
+
top: viewerBounds.top + viewerBounds.height / 2,
|
|
3352
|
+
transform: "translateY(-50%)"
|
|
3353
|
+
},
|
|
3354
|
+
children: [
|
|
3355
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3356
|
+
"button",
|
|
3357
|
+
{
|
|
3358
|
+
onClick: () => navigateBy(-1),
|
|
3359
|
+
disabled: !canGoPrev,
|
|
3360
|
+
className: `pointer-events-auto h-12 w-9 sm:h-14 sm:w-10 rounded-lg border backdrop-blur-md transition-all ${!canGoPrev ? "opacity-40 cursor-not-allowed" : "hover:scale-[1.03] active:scale-95"} ${isDark ? "bg-[#111827]/85 text-gray-100" : "bg-white/90 text-gray-700"}`,
|
|
3361
|
+
style: {
|
|
3362
|
+
borderColor: withAlpha3(accentColor, isDark ? 0.45 : 0.3),
|
|
3363
|
+
color: !canGoPrev ? void 0 : accentColor,
|
|
3364
|
+
boxShadow: `0 10px 24px ${withAlpha3(
|
|
3365
|
+
accentColor,
|
|
3366
|
+
isDark ? 0.18 : 0.12
|
|
3367
|
+
)}`
|
|
3368
|
+
},
|
|
3369
|
+
"aria-label": "Cap\xEDtulo anterior",
|
|
3370
|
+
title: "Cap\xEDtulo anterior",
|
|
3371
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3372
|
+
"svg",
|
|
3373
|
+
{
|
|
3374
|
+
className: "w-5 h-5 mx-auto",
|
|
3375
|
+
fill: "none",
|
|
3376
|
+
stroke: "currentColor",
|
|
3377
|
+
viewBox: "0 0 24 24",
|
|
3378
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3379
|
+
"path",
|
|
3380
|
+
{
|
|
3381
|
+
strokeLinecap: "round",
|
|
3382
|
+
strokeLinejoin: "round",
|
|
3383
|
+
strokeWidth: 2,
|
|
3384
|
+
d: "M15 19l-7-7 7-7"
|
|
3385
|
+
}
|
|
3386
|
+
)
|
|
3387
|
+
}
|
|
3388
|
+
)
|
|
3389
|
+
}
|
|
3390
|
+
),
|
|
3391
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3392
|
+
"button",
|
|
3393
|
+
{
|
|
3394
|
+
onClick: () => navigateBy(1),
|
|
3395
|
+
disabled: !canGoNext,
|
|
3396
|
+
className: `pointer-events-auto h-12 w-9 sm:h-14 sm:w-10 rounded-lg border backdrop-blur-md transition-all ${!canGoNext ? "opacity-40 cursor-not-allowed" : "hover:scale-[1.03] active:scale-95"} ${isDark ? "bg-[#111827]/85 text-gray-100" : "bg-white/90 text-gray-700"}`,
|
|
3397
|
+
style: {
|
|
3398
|
+
borderColor: withAlpha3(accentColor, isDark ? 0.45 : 0.3),
|
|
3399
|
+
color: !canGoNext ? void 0 : accentColor,
|
|
3400
|
+
boxShadow: `0 10px 24px ${withAlpha3(
|
|
3401
|
+
accentColor,
|
|
3402
|
+
isDark ? 0.18 : 0.12
|
|
3403
|
+
)}`
|
|
3404
|
+
},
|
|
3405
|
+
"aria-label": "Pr\xF3ximo cap\xEDtulo",
|
|
3406
|
+
title: "Pr\xF3ximo cap\xEDtulo",
|
|
3407
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3408
|
+
"svg",
|
|
3409
|
+
{
|
|
3410
|
+
className: "w-5 h-5 mx-auto",
|
|
3411
|
+
fill: "none",
|
|
3412
|
+
stroke: "currentColor",
|
|
3413
|
+
viewBox: "0 0 24 24",
|
|
3414
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3415
|
+
"path",
|
|
3416
|
+
{
|
|
3417
|
+
strokeLinecap: "round",
|
|
3418
|
+
strokeLinejoin: "round",
|
|
3419
|
+
strokeWidth: 2,
|
|
3420
|
+
d: "M9 5l7 7-7 7"
|
|
3421
|
+
}
|
|
3422
|
+
)
|
|
3423
|
+
}
|
|
3424
|
+
)
|
|
3425
|
+
}
|
|
3426
|
+
)
|
|
3427
|
+
]
|
|
3428
|
+
}
|
|
3429
|
+
),
|
|
3028
3430
|
toolDockOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3029
3431
|
"div",
|
|
3030
3432
|
{
|