@papyrus-sdk/ui-react 0.2.18 → 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/base.css CHANGED
@@ -1,45 +1,86 @@
1
1
  .papyrus-theme {
2
- --papyrus-bg: #f3f4f6;
3
- --papyrus-surface: #ffffff;
4
- --papyrus-surface-2: #f9fafb;
5
- --papyrus-border: #e5e7eb;
6
- --papyrus-border-strong: #d1d5db;
7
- --papyrus-text: #111827;
8
- --papyrus-text-muted: #6b7280;
9
- --papyrus-icon: #6b7280;
10
- --papyrus-focus: #93c5fd;
11
- --papyrus-canvas: #f3f4f6;
12
- --papyrus-hover: #e5e7eb;
13
- --papyrus-popover: #ffffff;
14
- --papyrus-shadow: rgba(15, 23, 42, 0.08);
15
- --papyrus-selection-bg: rgba(30, 64, 175, 0.5);
16
- color: var(--papyrus-text);
2
+ --papyrus-bg-fallback: #f3f4f6;
3
+ --papyrus-surface-fallback: #ffffff;
4
+ --papyrus-surface-2-fallback: #f9fafb;
5
+ --papyrus-border-fallback: #e5e7eb;
6
+ --papyrus-border-strong-fallback: #d1d5db;
7
+ --papyrus-text-fallback: #111827;
8
+ --papyrus-text-muted-fallback: #6b7280;
9
+ --papyrus-icon-fallback: #6b7280;
10
+ --papyrus-focus-fallback: #93c5fd;
11
+ --papyrus-canvas-fallback: #f3f4f6;
12
+ --papyrus-hover-fallback: #e5e7eb;
13
+ --papyrus-popover-fallback: #ffffff;
14
+ --papyrus-shadow-fallback: rgba(15, 23, 42, 0.08);
15
+ --papyrus-selection-bg-fallback: rgba(30, 64, 175, 0.5);
16
+ --papyrus-bg-resolved: var(--papyrus-bg, var(--papyrus-bg-fallback));
17
+ --papyrus-surface-resolved: var(
18
+ --papyrus-surface,
19
+ var(--papyrus-surface-fallback)
20
+ );
21
+ --papyrus-surface-2-resolved: var(
22
+ --papyrus-surface-2,
23
+ var(--papyrus-surface-2-fallback)
24
+ );
25
+ --papyrus-border-resolved: var(
26
+ --papyrus-border,
27
+ var(--papyrus-border-fallback)
28
+ );
29
+ --papyrus-border-strong-resolved: var(
30
+ --papyrus-border-strong,
31
+ var(--papyrus-border-strong-fallback)
32
+ );
33
+ --papyrus-text-resolved: var(--papyrus-text, var(--papyrus-text-fallback));
34
+ --papyrus-text-muted-resolved: var(
35
+ --papyrus-text-muted,
36
+ var(--papyrus-text-muted-fallback)
37
+ );
38
+ --papyrus-icon-resolved: var(--papyrus-icon, var(--papyrus-icon-fallback));
39
+ --papyrus-focus-resolved: var(--papyrus-focus, var(--papyrus-focus-fallback));
40
+ --papyrus-canvas-resolved: var(
41
+ --papyrus-canvas,
42
+ var(--papyrus-canvas-fallback)
43
+ );
44
+ --papyrus-hover-resolved: var(--papyrus-hover, var(--papyrus-hover-fallback));
45
+ --papyrus-popover-resolved: var(
46
+ --papyrus-popover,
47
+ var(--papyrus-popover-fallback)
48
+ );
49
+ --papyrus-shadow-resolved: var(
50
+ --papyrus-shadow,
51
+ var(--papyrus-shadow-fallback)
52
+ );
53
+ --papyrus-selection-bg-resolved: var(
54
+ --papyrus-selection-bg,
55
+ var(--papyrus-selection-bg-fallback)
56
+ );
57
+ color: var(--papyrus-text-resolved);
17
58
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
18
59
  }
19
60
 
20
61
  .papyrus-theme[data-papyrus-theme="dark"] {
21
- --papyrus-bg: #0f1115;
22
- --papyrus-surface: #1a1a1a;
23
- --papyrus-surface-2: #222222;
24
- --papyrus-border: #333333;
25
- --papyrus-border-strong: #444444;
26
- --papyrus-text: #f3f4f6;
27
- --papyrus-text-muted: #9ca3af;
28
- --papyrus-icon: #9ca3af;
29
- --papyrus-focus: #2563eb;
30
- --papyrus-canvas: #121212;
31
- --papyrus-hover: rgba(255, 255, 255, 0.08);
32
- --papyrus-popover: #1f1f1f;
33
- --papyrus-shadow: rgba(0, 0, 0, 0.4);
34
- --papyrus-selection-bg: rgba(96, 165, 250, 0.5);
62
+ --papyrus-bg-fallback: #0f1115;
63
+ --papyrus-surface-fallback: #1a1a1a;
64
+ --papyrus-surface-2-fallback: #222222;
65
+ --papyrus-border-fallback: #333333;
66
+ --papyrus-border-strong-fallback: #444444;
67
+ --papyrus-text-fallback: #f3f4f6;
68
+ --papyrus-text-muted-fallback: #9ca3af;
69
+ --papyrus-icon-fallback: #9ca3af;
70
+ --papyrus-focus-fallback: #2563eb;
71
+ --papyrus-canvas-fallback: #121212;
72
+ --papyrus-hover-fallback: rgba(255, 255, 255, 0.08);
73
+ --papyrus-popover-fallback: #1f1f1f;
74
+ --papyrus-shadow-fallback: rgba(0, 0, 0, 0.4);
75
+ --papyrus-selection-bg-fallback: rgba(96, 165, 250, 0.5);
35
76
  }
36
77
 
37
78
  .papyrus-topbar,
38
79
  .papyrus-sidebar-left,
39
80
  .papyrus-sidebar-right {
40
- background: var(--papyrus-surface) !important;
41
- border-color: var(--papyrus-border) !important;
42
- color: var(--papyrus-text) !important;
81
+ background: var(--papyrus-surface-resolved) !important;
82
+ border-color: var(--papyrus-border-resolved) !important;
83
+ color: var(--papyrus-text-resolved) !important;
43
84
  box-sizing: border-box;
44
85
  font-size: 13px;
45
86
  line-height: 1.4;
@@ -99,33 +140,33 @@
99
140
  }
100
141
 
101
142
  .papyrus-viewer {
102
- background: var(--papyrus-canvas) !important;
143
+ background: var(--papyrus-canvas-resolved) !important;
103
144
  box-sizing: border-box;
104
145
  flex: 1 1 auto;
105
146
  overflow-x: hidden;
106
147
  overflow-y: scroll;
107
148
  scrollbar-gutter: stable;
108
- color: var(--papyrus-text);
149
+ color: var(--papyrus-text-resolved);
109
150
  }
110
151
 
111
152
  .papyrus-control,
112
153
  .papyrus-input,
113
154
  .papyrus-popover {
114
- background: var(--papyrus-surface-2) !important;
115
- border-color: var(--papyrus-border) !important;
116
- color: var(--papyrus-text) !important;
155
+ background: var(--papyrus-surface-2-resolved) !important;
156
+ border-color: var(--papyrus-border-resolved) !important;
157
+ color: var(--papyrus-text-resolved) !important;
117
158
  }
118
159
 
119
160
  .papyrus-popover {
120
- background: var(--papyrus-popover) !important;
121
- box-shadow: 0 20px 40px var(--papyrus-shadow);
161
+ background: var(--papyrus-popover-resolved) !important;
162
+ box-shadow: 0 20px 40px var(--papyrus-shadow-resolved);
122
163
  }
123
164
 
124
165
  .papyrus-topbar button,
125
166
  .papyrus-sidebar-left button,
126
167
  .papyrus-sidebar-right button {
127
- background: var(--papyrus-surface-2);
128
- border: 1px solid var(--papyrus-border);
168
+ background: var(--papyrus-surface-2-resolved);
169
+ border: 1px solid var(--papyrus-border-resolved);
129
170
  border-radius: 8px;
130
171
  color: inherit;
131
172
  cursor: pointer;
@@ -146,11 +187,11 @@
146
187
  .papyrus-topbar select,
147
188
  .papyrus-sidebar-left select,
148
189
  .papyrus-sidebar-right select {
149
- background: var(--papyrus-surface);
150
- border: 1px solid var(--papyrus-border);
190
+ background: var(--papyrus-surface-resolved);
191
+ border: 1px solid var(--papyrus-border-resolved);
151
192
  border-radius: 6px;
152
193
  box-sizing: border-box;
153
- color: var(--papyrus-text);
194
+ color: var(--papyrus-text-resolved);
154
195
  font: inherit;
155
196
  padding: 6px 8px;
156
197
  }
@@ -158,8 +199,8 @@
158
199
  .papyrus-topbar button:hover,
159
200
  .papyrus-sidebar-left button:hover,
160
201
  .papyrus-sidebar-right button:hover {
161
- background: var(--papyrus-hover);
162
- border-color: var(--papyrus-border-strong);
202
+ background: var(--papyrus-hover-resolved);
203
+ border-color: var(--papyrus-border-strong-resolved);
163
204
  }
164
205
 
165
206
  .papyrus-topbar svg,
@@ -174,7 +215,7 @@
174
215
  .papyrus-topbar select:focus,
175
216
  .papyrus-sidebar-left select:focus,
176
217
  .papyrus-sidebar-right select:focus {
177
- outline: 2px solid var(--papyrus-focus);
218
+ outline: 2px solid var(--papyrus-focus-resolved);
178
219
  outline-offset: 1px;
179
220
  }
180
221
 
@@ -190,7 +231,7 @@
190
231
  }
191
232
 
192
233
  .papyrus-viewer .textLayer ::selection {
193
- background: var(--papyrus-selection-bg);
234
+ background: var(--papyrus-selection-bg-resolved);
194
235
  }
195
236
 
196
237
  .papyrus-viewer .textLayer {
package/dist/index.d.mts CHANGED
@@ -6,6 +6,7 @@ interface TopbarProps {
6
6
  showBrand?: boolean;
7
7
  brand?: React.ReactNode;
8
8
  title?: React.ReactNode;
9
+ style?: React.CSSProperties;
9
10
  showSidebarLeftToggle?: boolean;
10
11
  showPageControls?: boolean;
11
12
  showZoomControls?: boolean;
@@ -18,16 +19,19 @@ declare const Topbar: React.FC<TopbarProps>;
18
19
 
19
20
  interface SidebarLeftProps {
20
21
  engine: DocumentEngine;
22
+ style?: React.CSSProperties;
21
23
  }
22
24
  declare const SidebarLeft: React.FC<SidebarLeftProps>;
23
25
 
24
26
  interface SidebarRightProps {
25
27
  engine: DocumentEngine;
28
+ style?: React.CSSProperties;
26
29
  }
27
30
  declare const SidebarRight: React.FC<SidebarRightProps>;
28
31
 
29
32
  interface ViewerProps {
30
33
  engine: DocumentEngine;
34
+ style?: React.CSSProperties;
31
35
  }
32
36
  declare const Viewer: React.FC<ViewerProps>;
33
37
 
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ interface TopbarProps {
6
6
  showBrand?: boolean;
7
7
  brand?: React.ReactNode;
8
8
  title?: React.ReactNode;
9
+ style?: React.CSSProperties;
9
10
  showSidebarLeftToggle?: boolean;
10
11
  showPageControls?: boolean;
11
12
  showZoomControls?: boolean;
@@ -18,16 +19,19 @@ declare const Topbar: React.FC<TopbarProps>;
18
19
 
19
20
  interface SidebarLeftProps {
20
21
  engine: DocumentEngine;
22
+ style?: React.CSSProperties;
21
23
  }
22
24
  declare const SidebarLeft: React.FC<SidebarLeftProps>;
23
25
 
24
26
  interface SidebarRightProps {
25
27
  engine: DocumentEngine;
28
+ style?: React.CSSProperties;
26
29
  }
27
30
  declare const SidebarRight: React.FC<SidebarRightProps>;
28
31
 
29
32
  interface ViewerProps {
30
33
  engine: DocumentEngine;
34
+ style?: React.CSSProperties;
31
35
  }
32
36
  declare const Viewer: React.FC<ViewerProps>;
33
37
 
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ var Topbar = ({
37
37
  showBrand = false,
38
38
  brand,
39
39
  title,
40
+ style,
40
41
  showSidebarLeftToggle = true,
41
42
  showPageControls = true,
42
43
  showZoomControls = true,
@@ -45,6 +46,7 @@ var Topbar = ({
45
46
  showUpload = true,
46
47
  showSearch = true
47
48
  }) => {
49
+ const viewerState = (0, import_core.useViewerStore)();
48
50
  const {
49
51
  currentPage,
50
52
  pageCount,
@@ -57,13 +59,15 @@ var Topbar = ({
57
59
  toggleSidebarLeft,
58
60
  toggleSidebarRight,
59
61
  triggerScrollToPage
60
- } = (0, import_core.useViewerStore)();
62
+ } = viewerState;
63
+ const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
61
64
  const fileInputRef = (0, import_react.useRef)(null);
62
65
  const zoomTimerRef = (0, import_react.useRef)(null);
63
66
  const pendingZoomRef = (0, import_react.useRef)(null);
64
67
  const [pageInput, setPageInput] = (0, import_react.useState)(currentPage.toString());
65
68
  const [showPageThemes, setShowPageThemes] = (0, import_react.useState)(false);
66
69
  const [showMobileMenu, setShowMobileMenu] = (0, import_react.useState)(false);
70
+ const [isMobileViewport, setIsMobileViewport] = (0, import_react.useState)(false);
67
71
  const pageDigits = Math.max(2, String(pageCount || 1).length);
68
72
  const isDark = uiTheme === "dark";
69
73
  const canUseDOM = typeof document !== "undefined";
@@ -80,6 +84,18 @@ var Topbar = ({
80
84
  (0, import_react.useEffect)(() => {
81
85
  if (!hasMobileMenu) setShowMobileMenu(false);
82
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]);
83
99
  (0, import_react.useEffect)(() => {
84
100
  if (!showMobileMenu || !canUseDOM) return;
85
101
  const previousOverflow = document.body.style.overflow;
@@ -93,6 +109,30 @@ var Topbar = ({
93
109
  window.removeEventListener("keydown", handleKeyDown);
94
110
  };
95
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]);
96
136
  const handleZoom = (delta) => {
97
137
  const baseZoom = pendingZoomRef.current ?? zoom;
98
138
  const nextZoom = Math.max(0.2, Math.min(5, baseZoom + delta));
@@ -383,6 +423,7 @@ var Topbar = ({
383
423
  {
384
424
  "data-papyrus-theme": uiTheme,
385
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"}`,
426
+ style: topbarStyle,
386
427
  children: [
387
428
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 min-w-0 z-10", children: [
388
429
  showSidebarLeftToggle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -915,7 +956,7 @@ var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
915
956
  )) })
916
957
  ] });
917
958
  };
918
- var SidebarLeft = ({ engine }) => {
959
+ var SidebarLeft = ({ engine, style }) => {
919
960
  const {
920
961
  pageCount,
921
962
  currentPage,
@@ -937,6 +978,7 @@ var SidebarLeft = ({ engine }) => {
937
978
  {
938
979
  "data-papyrus-theme": uiTheme,
939
980
  className: `papyrus-sidebar-left papyrus-theme absolute left-0 top-0 bottom-0 z-[120] w-[85vw] max-w-72 border-r flex flex-col h-full overflow-hidden transition-colors duration-200 ${isDark ? "bg-[#2a2a2a] border-[#3a3a3a]" : "bg-[#fcfcfc] border-gray-200"}`,
981
+ style,
940
982
  children: [
941
983
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
942
984
  "div",
@@ -1077,7 +1119,7 @@ var withAlpha2 = (hex, alpha) => {
1077
1119
  const b = parseInt(value.slice(4, 6), 16);
1078
1120
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
1079
1121
  };
1080
- var SidebarRight = ({ engine }) => {
1122
+ var SidebarRight = ({ engine, style }) => {
1081
1123
  const {
1082
1124
  sidebarRightOpen,
1083
1125
  sidebarRightTab,
@@ -1114,6 +1156,7 @@ var SidebarRight = ({ engine }) => {
1114
1156
  {
1115
1157
  "data-papyrus-theme": uiTheme,
1116
1158
  className: `papyrus-sidebar-right papyrus-theme absolute right-0 top-0 bottom-0 z-[120] w-[88vw] max-w-80 border-l flex flex-col h-full transition-colors duration-200 shadow-2xl ${isDark ? "bg-[#1a1a1a] border-[#333]" : "bg-white border-gray-200"}`,
1159
+ style,
1117
1160
  children: [
1118
1161
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1119
1162
  "div",
@@ -2106,7 +2149,11 @@ var MIN_ZOOM = 0.2;
2106
2149
  var MAX_ZOOM = 5;
2107
2150
  var WIDTH_SNAP_PX = 4;
2108
2151
  var WIDTH_HYSTERESIS_PX = 6;
2109
- var Viewer = ({ engine }) => {
2152
+ var MOBILE_HEADER_HIDE_DELTA_PX = 28;
2153
+ var MOBILE_HEADER_SHOW_DELTA_PX = 16;
2154
+ var MOBILE_HEADER_TOP_RESET_PX = 12;
2155
+ var Viewer = ({ engine, style }) => {
2156
+ const viewerState = (0, import_core5.useViewerStore)();
2110
2157
  const {
2111
2158
  pageCount,
2112
2159
  currentPage,
@@ -2119,7 +2166,8 @@ var Viewer = ({ engine }) => {
2119
2166
  annotationColor,
2120
2167
  setAnnotationColor,
2121
2168
  toolDockOpen
2122
- } = (0, import_core5.useViewerStore)();
2169
+ } = viewerState;
2170
+ const mobileTopbarVisible = viewerState.mobileTopbarVisible ?? true;
2123
2171
  const isDark = uiTheme === "dark";
2124
2172
  const viewerRef = (0, import_react5.useRef)(null);
2125
2173
  const colorPickerRef = (0, import_react5.useRef)(null);
@@ -2129,6 +2177,11 @@ var Viewer = ({ engine }) => {
2129
2177
  const jumpRef = (0, import_react5.useRef)(false);
2130
2178
  const jumpTimerRef = (0, import_react5.useRef)(null);
2131
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);
2132
2185
  const pinchRef = (0, import_react5.useRef)({
2133
2186
  active: false,
2134
2187
  startDistance: 0,
@@ -2141,6 +2194,7 @@ var Viewer = ({ engine }) => {
2141
2194
  const [pageSizes, setPageSizes] = (0, import_react5.useState)({});
2142
2195
  const [colorPickerOpen, setColorPickerOpen] = (0, import_react5.useState)(false);
2143
2196
  const isCompact = availableWidth !== null && availableWidth < 820;
2197
+ const isMobileViewport = availableWidth !== null && availableWidth < 640;
2144
2198
  const paddingY = isCompact ? "py-10" : "py-16";
2145
2199
  const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
2146
2200
  const colorPalette = [
@@ -2153,6 +2207,13 @@ var Viewer = ({ engine }) => {
2153
2207
  "#8b5cf6",
2154
2208
  "#111827"
2155
2209
  ];
2210
+ const setMobileTopbarVisibility = (visible) => {
2211
+ if (mobileTopbarVisibleRef.current === visible) return;
2212
+ mobileTopbarVisibleRef.current = visible;
2213
+ setDocumentState({
2214
+ mobileTopbarVisible: visible
2215
+ });
2216
+ };
2156
2217
  (0, import_react5.useEffect)(() => {
2157
2218
  if (!colorPickerOpen) return;
2158
2219
  const handleClick = (event) => {
@@ -2167,6 +2228,9 @@ var Viewer = ({ engine }) => {
2167
2228
  (0, import_react5.useEffect)(() => {
2168
2229
  if (!toolDockOpen && colorPickerOpen) setColorPickerOpen(false);
2169
2230
  }, [toolDockOpen, colorPickerOpen]);
2231
+ (0, import_react5.useEffect)(() => {
2232
+ mobileTopbarVisibleRef.current = mobileTopbarVisible;
2233
+ }, [mobileTopbarVisible]);
2170
2234
  (0, import_react5.useEffect)(
2171
2235
  () => () => {
2172
2236
  if (pinchRef.current.rafId != null) {
@@ -2218,6 +2282,64 @@ var Viewer = ({ engine }) => {
2218
2282
  observer.disconnect();
2219
2283
  };
2220
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]);
2221
2343
  (0, import_react5.useEffect)(() => {
2222
2344
  let active = true;
2223
2345
  if (!pageCount) return;
@@ -2449,6 +2571,7 @@ var Viewer = ({ engine }) => {
2449
2571
  onTouchEnd: handleTouchEnd,
2450
2572
  onTouchCancel: handleTouchEnd,
2451
2573
  className: `papyrus-viewer papyrus-theme min-w-0 w-full flex-1 overflow-y-scroll overflow-x-hidden flex flex-col items-center ${paddingY} relative custom-scrollbar scroll-smooth ${isDark ? "bg-[#121212]" : "bg-[#e9ecef]"}`,
2574
+ style,
2452
2575
  children: [
2453
2576
  /* @__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)(
2454
2577
  "div",