@papyrus-sdk/ui-react 0.2.19 → 0.2.20
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 +121 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +129 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ var Topbar = ({
|
|
|
46
46
|
showUpload = true,
|
|
47
47
|
showSearch = true
|
|
48
48
|
}) => {
|
|
49
|
+
const viewerState = (0, import_core.useViewerStore)();
|
|
49
50
|
const {
|
|
50
51
|
currentPage,
|
|
51
52
|
pageCount,
|
|
@@ -58,13 +59,15 @@ var Topbar = ({
|
|
|
58
59
|
toggleSidebarLeft,
|
|
59
60
|
toggleSidebarRight,
|
|
60
61
|
triggerScrollToPage
|
|
61
|
-
} =
|
|
62
|
+
} = viewerState;
|
|
63
|
+
const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
|
|
62
64
|
const fileInputRef = (0, import_react.useRef)(null);
|
|
63
65
|
const zoomTimerRef = (0, import_react.useRef)(null);
|
|
64
66
|
const pendingZoomRef = (0, import_react.useRef)(null);
|
|
65
67
|
const [pageInput, setPageInput] = (0, import_react.useState)(currentPage.toString());
|
|
66
68
|
const [showPageThemes, setShowPageThemes] = (0, import_react.useState)(false);
|
|
67
69
|
const [showMobileMenu, setShowMobileMenu] = (0, import_react.useState)(false);
|
|
70
|
+
const [isMobileViewport, setIsMobileViewport] = (0, import_react.useState)(false);
|
|
68
71
|
const pageDigits = Math.max(2, String(pageCount || 1).length);
|
|
69
72
|
const isDark = uiTheme === "dark";
|
|
70
73
|
const canUseDOM = typeof document !== "undefined";
|
|
@@ -81,6 +84,18 @@ var Topbar = ({
|
|
|
81
84
|
(0, import_react.useEffect)(() => {
|
|
82
85
|
if (!hasMobileMenu) setShowMobileMenu(false);
|
|
83
86
|
}, [hasMobileMenu]);
|
|
87
|
+
(0, import_react.useEffect)(() => {
|
|
88
|
+
if (!canUseDOM || typeof window.matchMedia !== "function") return;
|
|
89
|
+
const mediaQuery = window.matchMedia("(max-width: 639px)");
|
|
90
|
+
const updateViewport = () => setIsMobileViewport(mediaQuery.matches);
|
|
91
|
+
updateViewport();
|
|
92
|
+
if (typeof mediaQuery.addEventListener === "function") {
|
|
93
|
+
mediaQuery.addEventListener("change", updateViewport);
|
|
94
|
+
return () => mediaQuery.removeEventListener("change", updateViewport);
|
|
95
|
+
}
|
|
96
|
+
mediaQuery.addListener(updateViewport);
|
|
97
|
+
return () => mediaQuery.removeListener(updateViewport);
|
|
98
|
+
}, [canUseDOM]);
|
|
84
99
|
(0, import_react.useEffect)(() => {
|
|
85
100
|
if (!showMobileMenu || !canUseDOM) return;
|
|
86
101
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -94,6 +109,30 @@ var Topbar = ({
|
|
|
94
109
|
window.removeEventListener("keydown", handleKeyDown);
|
|
95
110
|
};
|
|
96
111
|
}, [showMobileMenu, canUseDOM]);
|
|
112
|
+
const topbarStyle = (0, import_react.useMemo)(() => {
|
|
113
|
+
const mergedStyle = { ...style ?? {} };
|
|
114
|
+
if (!isMobileViewport) {
|
|
115
|
+
mergedStyle.transition = "height 180ms ease, opacity 160ms ease, padding 180ms ease, border-width 180ms ease";
|
|
116
|
+
return mergedStyle;
|
|
117
|
+
}
|
|
118
|
+
mergedStyle.transition = "height 180ms ease, opacity 160ms ease, padding 180ms ease, border-width 180ms ease";
|
|
119
|
+
mergedStyle.overflow = "hidden";
|
|
120
|
+
if (!mobileTopbarVisible) {
|
|
121
|
+
mergedStyle.height = 0;
|
|
122
|
+
mergedStyle.minHeight = 0;
|
|
123
|
+
mergedStyle.paddingTop = 0;
|
|
124
|
+
mergedStyle.paddingBottom = 0;
|
|
125
|
+
mergedStyle.borderBottomWidth = 0;
|
|
126
|
+
mergedStyle.opacity = 0;
|
|
127
|
+
mergedStyle.pointerEvents = "none";
|
|
128
|
+
return mergedStyle;
|
|
129
|
+
}
|
|
130
|
+
mergedStyle.height = 56;
|
|
131
|
+
mergedStyle.minHeight = 56;
|
|
132
|
+
mergedStyle.opacity = 1;
|
|
133
|
+
mergedStyle.pointerEvents = "auto";
|
|
134
|
+
return mergedStyle;
|
|
135
|
+
}, [isMobileViewport, mobileTopbarVisible, style]);
|
|
97
136
|
const handleZoom = (delta) => {
|
|
98
137
|
const baseZoom = pendingZoomRef.current ?? zoom;
|
|
99
138
|
const nextZoom = Math.max(0.2, Math.min(5, baseZoom + delta));
|
|
@@ -384,7 +423,7 @@ var Topbar = ({
|
|
|
384
423
|
{
|
|
385
424
|
"data-papyrus-theme": uiTheme,
|
|
386
425
|
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"}`,
|
|
387
|
-
style,
|
|
426
|
+
style: topbarStyle,
|
|
388
427
|
children: [
|
|
389
428
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 min-w-0 z-10", children: [
|
|
390
429
|
showSidebarLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -2110,7 +2149,11 @@ var MIN_ZOOM = 0.2;
|
|
|
2110
2149
|
var MAX_ZOOM = 5;
|
|
2111
2150
|
var WIDTH_SNAP_PX = 4;
|
|
2112
2151
|
var WIDTH_HYSTERESIS_PX = 6;
|
|
2152
|
+
var MOBILE_HEADER_HIDE_DELTA_PX = 28;
|
|
2153
|
+
var MOBILE_HEADER_SHOW_DELTA_PX = 16;
|
|
2154
|
+
var MOBILE_HEADER_TOP_RESET_PX = 12;
|
|
2113
2155
|
var Viewer = ({ engine, style }) => {
|
|
2156
|
+
const viewerState = (0, import_core5.useViewerStore)();
|
|
2114
2157
|
const {
|
|
2115
2158
|
pageCount,
|
|
2116
2159
|
currentPage,
|
|
@@ -2123,7 +2166,8 @@ var Viewer = ({ engine, style }) => {
|
|
|
2123
2166
|
annotationColor,
|
|
2124
2167
|
setAnnotationColor,
|
|
2125
2168
|
toolDockOpen
|
|
2126
|
-
} =
|
|
2169
|
+
} = viewerState;
|
|
2170
|
+
const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
|
|
2127
2171
|
const isDark = uiTheme === "dark";
|
|
2128
2172
|
const viewerRef = (0, import_react5.useRef)(null);
|
|
2129
2173
|
const colorPickerRef = (0, import_react5.useRef)(null);
|
|
@@ -2133,6 +2177,11 @@ var Viewer = ({ engine, style }) => {
|
|
|
2133
2177
|
const jumpRef = (0, import_react5.useRef)(false);
|
|
2134
2178
|
const jumpTimerRef = (0, import_react5.useRef)(null);
|
|
2135
2179
|
const lastWidthRef = (0, import_react5.useRef)(null);
|
|
2180
|
+
const lastScrollTopRef = (0, import_react5.useRef)(0);
|
|
2181
|
+
const scrollDownAccumulatorRef = (0, import_react5.useRef)(0);
|
|
2182
|
+
const scrollUpAccumulatorRef = (0, import_react5.useRef)(0);
|
|
2183
|
+
const previousCurrentPageRef = (0, import_react5.useRef)(currentPage);
|
|
2184
|
+
const mobileTopbarVisibleRef = (0, import_react5.useRef)(mobileTopbarVisible);
|
|
2136
2185
|
const pinchRef = (0, import_react5.useRef)({
|
|
2137
2186
|
active: false,
|
|
2138
2187
|
startDistance: 0,
|
|
@@ -2145,6 +2194,7 @@ var Viewer = ({ engine, style }) => {
|
|
|
2145
2194
|
const [pageSizes, setPageSizes] = (0, import_react5.useState)({});
|
|
2146
2195
|
const [colorPickerOpen, setColorPickerOpen] = (0, import_react5.useState)(false);
|
|
2147
2196
|
const isCompact = availableWidth !== null && availableWidth < 820;
|
|
2197
|
+
const isMobileViewport = availableWidth !== null && availableWidth < 640;
|
|
2148
2198
|
const paddingY = isCompact ? "py-10" : "py-16";
|
|
2149
2199
|
const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
|
|
2150
2200
|
const colorPalette = [
|
|
@@ -2157,6 +2207,13 @@ var Viewer = ({ engine, style }) => {
|
|
|
2157
2207
|
"#8b5cf6",
|
|
2158
2208
|
"#111827"
|
|
2159
2209
|
];
|
|
2210
|
+
const setMobileTopbarVisibility = (visible) => {
|
|
2211
|
+
if (mobileTopbarVisibleRef.current === visible) return;
|
|
2212
|
+
mobileTopbarVisibleRef.current = visible;
|
|
2213
|
+
setDocumentState({
|
|
2214
|
+
mobileTopbarVisible: visible
|
|
2215
|
+
});
|
|
2216
|
+
};
|
|
2160
2217
|
(0, import_react5.useEffect)(() => {
|
|
2161
2218
|
if (!colorPickerOpen) return;
|
|
2162
2219
|
const handleClick = (event) => {
|
|
@@ -2171,6 +2228,9 @@ var Viewer = ({ engine, style }) => {
|
|
|
2171
2228
|
(0, import_react5.useEffect)(() => {
|
|
2172
2229
|
if (!toolDockOpen && colorPickerOpen) setColorPickerOpen(false);
|
|
2173
2230
|
}, [toolDockOpen, colorPickerOpen]);
|
|
2231
|
+
(0, import_react5.useEffect)(() => {
|
|
2232
|
+
mobileTopbarVisibleRef.current = mobileTopbarVisible;
|
|
2233
|
+
}, [mobileTopbarVisible]);
|
|
2174
2234
|
(0, import_react5.useEffect)(
|
|
2175
2235
|
() => () => {
|
|
2176
2236
|
if (pinchRef.current.rafId != null) {
|
|
@@ -2222,6 +2282,64 @@ var Viewer = ({ engine, style }) => {
|
|
|
2222
2282
|
observer.disconnect();
|
|
2223
2283
|
};
|
|
2224
2284
|
}, []);
|
|
2285
|
+
(0, import_react5.useEffect)(() => {
|
|
2286
|
+
const root = viewerRef.current;
|
|
2287
|
+
if (!root) return;
|
|
2288
|
+
if (!isMobileViewport) {
|
|
2289
|
+
lastScrollTopRef.current = root.scrollTop;
|
|
2290
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2291
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2292
|
+
setMobileTopbarVisibility(true);
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
lastScrollTopRef.current = root.scrollTop;
|
|
2296
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2297
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2298
|
+
const handleScroll = () => {
|
|
2299
|
+
const nextScrollTop = root.scrollTop;
|
|
2300
|
+
const delta = nextScrollTop - lastScrollTopRef.current;
|
|
2301
|
+
lastScrollTopRef.current = nextScrollTop;
|
|
2302
|
+
if (Math.abs(delta) < 1) return;
|
|
2303
|
+
if (nextScrollTop <= MOBILE_HEADER_TOP_RESET_PX) {
|
|
2304
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2305
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2306
|
+
setMobileTopbarVisibility(true);
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
if (delta > 0) {
|
|
2310
|
+
scrollDownAccumulatorRef.current += delta;
|
|
2311
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2312
|
+
} else {
|
|
2313
|
+
scrollUpAccumulatorRef.current += -delta;
|
|
2314
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2315
|
+
}
|
|
2316
|
+
if (scrollDownAccumulatorRef.current >= MOBILE_HEADER_HIDE_DELTA_PX && mobileTopbarVisibleRef.current) {
|
|
2317
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2318
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2319
|
+
setMobileTopbarVisibility(false);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
if (scrollUpAccumulatorRef.current >= MOBILE_HEADER_SHOW_DELTA_PX && !mobileTopbarVisibleRef.current) {
|
|
2323
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2324
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2325
|
+
setMobileTopbarVisibility(true);
|
|
2326
|
+
}
|
|
2327
|
+
};
|
|
2328
|
+
root.addEventListener("scroll", handleScroll, { passive: true });
|
|
2329
|
+
return () => {
|
|
2330
|
+
root.removeEventListener("scroll", handleScroll);
|
|
2331
|
+
};
|
|
2332
|
+
}, [isMobileViewport, setDocumentState]);
|
|
2333
|
+
(0, import_react5.useEffect)(() => {
|
|
2334
|
+
const previousPage = previousCurrentPageRef.current;
|
|
2335
|
+
previousCurrentPageRef.current = currentPage;
|
|
2336
|
+
if (!isMobileViewport) return;
|
|
2337
|
+
if (currentPage < previousPage && !mobileTopbarVisibleRef.current) {
|
|
2338
|
+
scrollDownAccumulatorRef.current = 0;
|
|
2339
|
+
scrollUpAccumulatorRef.current = 0;
|
|
2340
|
+
setMobileTopbarVisibility(true);
|
|
2341
|
+
}
|
|
2342
|
+
}, [currentPage, isMobileViewport, setDocumentState]);
|
|
2225
2343
|
(0, import_react5.useEffect)(() => {
|
|
2226
2344
|
let active = true;
|
|
2227
2345
|
if (!pageCount) return;
|