@papyrus-sdk/ui-react-native 0.2.35-beta.10 → 0.2.35-beta.11

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.d.mts CHANGED
@@ -124,12 +124,17 @@ interface RightSheetProps {
124
124
  }
125
125
  declare const RightSheet: React.FC<RightSheetProps>;
126
126
 
127
- declare const AnnotationEditor: React.FC;
127
+ declare const AnnotationEditor: React.FC<{
128
+ documentId?: string;
129
+ }>;
128
130
 
129
131
  type BottomBarProps = {
130
132
  documentType: DocumentType;
131
133
  onOpenInfo: () => void;
132
134
  onOpenSettings: () => void;
135
+ onTurnPage?: (direction: -1 | 1) => void;
136
+ onNavigateToPage?: (page: number) => void;
137
+ onOpenPages?: () => void;
133
138
  onOpenDestination?: (destination: MobilePrimaryDestination) => void;
134
139
  };
135
140
  declare const BottomBar: React.FC<BottomBarProps>;
@@ -139,6 +144,7 @@ interface SettingsSheetProps {
139
144
  visible: boolean;
140
145
  onClose: () => void;
141
146
  documentType?: DocumentType;
147
+ onOpenInfo?: () => void;
142
148
  }
143
149
  declare const SettingsSheet: React.FC<SettingsSheetProps>;
144
150
 
@@ -208,12 +214,14 @@ declare function DocumentActionsSheet({ visible, onClose, }: DocumentActionsShee
208
214
 
209
215
  type ProgressPillProps = {
210
216
  documentType: DocumentType;
217
+ navigationInDock?: boolean;
211
218
  onPress: () => void;
212
219
  onOpenPageJump?: () => void;
213
220
  onNavigateToPage?: (page: number) => void;
221
+ onTurnPage?: (direction: -1 | 1) => void;
214
222
  onScrubbingChange?: (active: boolean) => void;
215
223
  };
216
- declare function ProgressPill({ documentType, onPress, onOpenPageJump, onNavigateToPage, onScrubbingChange, }: ProgressPillProps): react_jsx_runtime.JSX.Element;
224
+ declare function ProgressPill({ documentType, navigationInDock, onPress, onOpenPageJump, onNavigateToPage, onTurnPage, onScrubbingChange, }: ProgressPillProps): react_jsx_runtime.JSX.Element;
217
225
 
218
226
  type SearchOverlayProps = {
219
227
  engine: DocumentEngine;
package/dist/index.d.ts CHANGED
@@ -124,12 +124,17 @@ interface RightSheetProps {
124
124
  }
125
125
  declare const RightSheet: React.FC<RightSheetProps>;
126
126
 
127
- declare const AnnotationEditor: React.FC;
127
+ declare const AnnotationEditor: React.FC<{
128
+ documentId?: string;
129
+ }>;
128
130
 
129
131
  type BottomBarProps = {
130
132
  documentType: DocumentType;
131
133
  onOpenInfo: () => void;
132
134
  onOpenSettings: () => void;
135
+ onTurnPage?: (direction: -1 | 1) => void;
136
+ onNavigateToPage?: (page: number) => void;
137
+ onOpenPages?: () => void;
133
138
  onOpenDestination?: (destination: MobilePrimaryDestination) => void;
134
139
  };
135
140
  declare const BottomBar: React.FC<BottomBarProps>;
@@ -139,6 +144,7 @@ interface SettingsSheetProps {
139
144
  visible: boolean;
140
145
  onClose: () => void;
141
146
  documentType?: DocumentType;
147
+ onOpenInfo?: () => void;
142
148
  }
143
149
  declare const SettingsSheet: React.FC<SettingsSheetProps>;
144
150
 
@@ -208,12 +214,14 @@ declare function DocumentActionsSheet({ visible, onClose, }: DocumentActionsShee
208
214
 
209
215
  type ProgressPillProps = {
210
216
  documentType: DocumentType;
217
+ navigationInDock?: boolean;
211
218
  onPress: () => void;
212
219
  onOpenPageJump?: () => void;
213
220
  onNavigateToPage?: (page: number) => void;
221
+ onTurnPage?: (direction: -1 | 1) => void;
214
222
  onScrubbingChange?: (active: boolean) => void;
215
223
  };
216
- declare function ProgressPill({ documentType, onPress, onOpenPageJump, onNavigateToPage, onScrubbingChange, }: ProgressPillProps): react_jsx_runtime.JSX.Element;
224
+ declare function ProgressPill({ documentType, navigationInDock, onPress, onOpenPageJump, onNavigateToPage, onTurnPage, onScrubbingChange, }: ProgressPillProps): react_jsx_runtime.JSX.Element;
217
225
 
218
226
  type SearchOverlayProps = {
219
227
  engine: DocumentEngine;
package/dist/index.js CHANGED
@@ -21833,6 +21833,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21833
21833
  if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
21834
21834
  }));
21835
21835
  rendition.on('relocated', (location) => {
21836
+ if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21836
21837
  const start = location && location.start;
21837
21838
  let index = start && Number.isInteger(start.index) ? start.index : -1;
21838
21839
  if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
@@ -21951,10 +21952,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21951
21952
  sendEvent('VIEWER_SCROLL', { offsetY });
21952
21953
  };
21953
21954
  const handleTouchStart = (event) => {
21954
- touchStart = getTouchPoint(event);
21955
+ touchStart = event?.touches?.length > 1 ? null : getTouchPoint(event);
21955
21956
  epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
21956
21957
  };
21957
21958
  const handleTouchMove = (event) => {
21959
+ if (event?.touches?.length > 1) touchStart = null;
21958
21960
  epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
21959
21961
  };
21960
21962
  const handleTouchEnd = (event) => {
@@ -21962,7 +21964,15 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21962
21964
  const start = touchStart;
21963
21965
  touchStart = null;
21964
21966
  const selectedText = event?.target?.ownerDocument?.defaultView?.getSelection?.()?.toString().trim() || '';
21965
- if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
21967
+ if (!selectedText && start && end && epubViewMode === 'single' && Math.abs(end.x-start.x) >= 48 && Math.abs(end.x-start.x) > Math.abs(end.y-start.y)*1.5) {
21968
+ const active = rendition;
21969
+ const interactionSession = documentSessionId;
21970
+ epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
21971
+ if (active !== rendition || interactionSession !== documentSessionId) return;
21972
+ return end.x < start.x ? active.next() : active.prev();
21973
+ });
21974
+ epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR', {message:String(error)}));
21975
+ } else if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
21966
21976
  sendEvent('VIEWER_TAP', {});
21967
21977
  }
21968
21978
  epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
@@ -22007,6 +22017,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22007
22017
  return { pageCount, outline };
22008
22018
  };
22009
22019
 
22020
+ let epubNavigationQueue = Promise.resolve();
22021
+ let epubNavigationRequest = 0;
22010
22022
  const displayEpubPage = async (pageIndex) => {
22011
22023
  if (!rendition) return;
22012
22024
  const item = spineItems[pageIndex];
@@ -22016,9 +22028,18 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22016
22028
  target,
22017
22029
  pageIndex,
22018
22030
  });
22019
- await rendition.display(target);
22020
- currentPage = pageIndex + 1;
22021
- sendState();
22031
+ const activeRendition = rendition;
22032
+ const session = documentSessionId;
22033
+ const request = ++epubNavigationRequest;
22034
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22035
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22036
+ await activeRendition.display(target);
22037
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22038
+ currentPage = pageIndex + 1;
22039
+ sendState();
22040
+ });
22041
+ epubNavigationQueue = navigation;
22042
+ await navigation;
22022
22043
  };
22023
22044
 
22024
22045
  const getTextContent = async (pageIndex) => {
@@ -22120,6 +22141,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22120
22141
  };
22121
22142
 
22122
22143
  let nativeMenuSelection = null;
22144
+ let epubViewMode = "continuous";
22123
22145
 
22124
22146
  const handleCommand = async (message) => {
22125
22147
  const { id, kind, payload } = message;
@@ -22132,6 +22154,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22132
22154
  epubAnnotations = [];
22133
22155
  annotationDocumentId = undefined;
22134
22156
  zoom = 1.0;
22157
+ epubViewMode = "continuous";
22158
+ epubNavigationRequest += 1;
22159
+ epubNavigationQueue = Promise.resolve();
22135
22160
 
22136
22161
  if (currentType === 'text') {
22137
22162
  const result = await loadText(
@@ -22186,17 +22211,23 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22186
22211
  epubAnnotationRenderers.forEach(renderer => renderer.schedule());
22187
22212
  } else {
22188
22213
  const annotation = epubAnnotations.find(a => a.id === payload.annotationId);
22189
- if (!annotation) throw new Error('Annotation not available');
22214
+ if (!annotation || (annotation.anchor.documentId && annotation.anchor.documentId !== annotationDocumentId)) throw new Error('Annotation not available for this document');
22190
22215
  // Navigation uses the CFI, never a synthetic percentage/page rectangle.
22191
22216
  const navigationSession = documentSessionId;
22192
22217
  const activeRendition = rendition;
22193
22218
  // Open the confirmed chapter first, resolve its quote, then navigate its actual range.
22194
- await activeRendition.display(annotation.anchor.href);
22195
- if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22196
- const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
22197
- const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
22198
- if(!range)throw new Error('EPUB anchor unresolved');
22199
- await activeRendition.display(contents.cfiFromRange(range));
22219
+ epubNavigationRequest += 1;
22220
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22221
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22222
+ await activeRendition.display(annotation.anchor.href);
22223
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22224
+ const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
22225
+ const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
22226
+ if(!range)throw new Error('EPUB anchor unresolved');
22227
+ await activeRendition.display(contents.cfiFromRange(range));
22228
+ });
22229
+ epubNavigationQueue = navigation;
22230
+ await navigation;
22200
22231
  }
22201
22232
  sendResponse(id,true,null); return;
22202
22233
  }
@@ -22223,6 +22254,33 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22223
22254
  return;
22224
22255
  }
22225
22256
 
22257
+ if (kind === 'epub-turn-page') {
22258
+ if (epubViewMode !== 'single') {sendResponse(id,true,null); return;}
22259
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB navigation');
22260
+ const active = rendition;
22261
+ epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22262
+ if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22263
+ return payload.direction < 0 ? active.prev() : active.next();
22264
+ });
22265
+ await epubNavigationQueue;
22266
+ sendResponse(id,true,null); return;
22267
+ }
22268
+
22269
+ if (kind === 'set-epub-view-mode') {
22270
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
22271
+ epubViewMode = payload.viewMode === 'single' ? 'single' : 'continuous';
22272
+ const active = rendition;
22273
+ epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22274
+ if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22275
+ const flow = epubViewMode === 'single' ? 'paginated' : 'scrolled-continuous';
22276
+ if (active.settings.flow === flow) return;
22277
+ active.flow(flow);
22278
+ return active.q.enqueue(() => Promise.resolve());
22279
+ });
22280
+ await epubNavigationQueue;
22281
+ sendResponse(id,true,null); return;
22282
+ }
22283
+
22226
22284
  if (kind === 'set-zoom') {
22227
22285
  zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
22228
22286
  applyZoom();
@@ -25980,7 +26038,7 @@ var WebViewViewer = ({
25980
26038
  onTap
25981
26039
  }) => {
25982
26040
  const webViewRef = (0, import_react3.useRef)(null);
25983
- const { pageTheme, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = (0, import_core4.useViewerStore)();
26041
+ const { pageTheme, viewMode, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = (0, import_core4.useViewerStore)();
25984
26042
  const [selection, setSelection] = (0, import_react3.useState)(null);
25985
26043
  const t = getStrings(locale);
25986
26044
  const bridgeEngine = engine;
@@ -26061,6 +26119,10 @@ var WebViewViewer = ({
26061
26119
  (note !== void 0 ? beginAnnotationDraft : addAnnotation)((0, import_core4.createContextualAnnotation)({ id: `annotation-${Date.now()}-${Math.random().toString(36).slice(2)}`, anchor: selected.anchor, pageIndex: selected.pageIndex, style, color: annotationColor, opacity: annotationOpacity, note }));
26062
26120
  setSelection(null);
26063
26121
  };
26122
+ (0, import_react3.useEffect)(() => {
26123
+ if (!isLoaded) return;
26124
+ webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { viewMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26125
+ }, [isLoaded, viewMode, bridgeEngine]);
26064
26126
  const sendSelectionCommand = (key) => {
26065
26127
  webViewRef.current?.postMessage(JSON.stringify({
26066
26128
  type: "epub-selection-action",
@@ -30247,6 +30309,7 @@ var Topbar = ({
30247
30309
  {
30248
30310
  style: [
30249
30311
  styles11.container,
30312
+ import_react_native13.Platform.OS === "ios" && styles11.containerIos,
30250
30313
  isDark && styles11.containerDark,
30251
30314
  isLandscape && styles11.containerLandscape
30252
30315
  ],
@@ -30403,7 +30466,8 @@ var styles11 = import_react_native13.StyleSheet.create({
30403
30466
  maxWidth: MOBILE_CHROME_METRICS.maxFloatingWidth,
30404
30467
  marginTop: 10,
30405
30468
  paddingHorizontal: 14,
30406
- paddingVertical: 10,
30469
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30470
+ paddingVertical: 0,
30407
30471
  backgroundColor: "rgba(255,255,255,0.88)",
30408
30472
  borderWidth: 1,
30409
30473
  borderColor: "rgba(255,255,255,0.72)",
@@ -30420,6 +30484,10 @@ var styles11 = import_react_native13.StyleSheet.create({
30420
30484
  backgroundColor: "rgba(15,17,21,0.88)",
30421
30485
  borderColor: "rgba(71,85,105,0.48)"
30422
30486
  },
30487
+ containerIos: {
30488
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30489
+ paddingVertical: 0
30490
+ },
30423
30491
  containerLandscape: {
30424
30492
  maxWidth: void 0,
30425
30493
  marginTop: 0
@@ -32556,10 +32624,10 @@ var import_react_native16 = require("react-native");
32556
32624
  var import_core15 = require("@papyrus-sdk/core");
32557
32625
  var import_jsx_runtime18 = require("react/jsx-runtime");
32558
32626
  var COLORS = ["#fbbf24", "#fb7185", "#60a5fa", "#34d399", "#c084fc"];
32559
- var AnnotationEditor = () => {
32627
+ var AnnotationEditor = ({ documentId }) => {
32560
32628
  const { annotations, annotationDraft, clearAnnotationDraft, addAnnotation, selectedAnnotationId, updateAnnotation, removeAnnotation, setSelectedAnnotation, uiTheme, locale, accentColor } = (0, import_core15.useViewerStore)();
32561
32629
  const annotation = annotationDraft?.id === selectedAnnotationId ? annotationDraft : annotations.find((a) => a.id === selectedAnnotationId);
32562
- const supported = annotation && annotation.type !== "ink";
32630
+ const supported = annotation && annotation.type !== "ink" && (!documentId || !annotation.anchor?.documentId || annotation.anchor.documentId === documentId);
32563
32631
  const [editing, setEditing] = (0, import_react16.useState)(false);
32564
32632
  const [draft, setDraft] = (0, import_react16.useState)("");
32565
32633
  const [color, setColor] = (0, import_react16.useState)(COLORS[0]);
@@ -32624,7 +32692,7 @@ var AnnotationEditor = () => {
32624
32692
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native16.Animated.View, { accessibilityViewIsModal: true, style: [styles14.card, { backgroundColor: dark ? "#17191f" : "#fff", marginBottom: Math.max(16, insets.bottom), opacity: progress, transform: [{ translateY: progress.interpolate({ inputRange: [0, 1], outputRange: [12, 0] }) }] }], children: [
32625
32693
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native16.View, { style: styles14.header, children: [
32626
32694
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: [styles14.title, textStyle], children: editing ? t.editNote : t.annotationNote }),
32627
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Pressable, { onPress: close, accessibilityRole: "button", accessibilityLabel: t.close, style: styles14.button, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: textStyle, children: "\xD7" }) })
32695
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Pressable, { onPress: close, accessibilityRole: "button", accessibilityLabel: t.close, style: [styles14.button, { borderRadius: 22, backgroundColor: dark ? "#242936" : "#f1f5f9" }], children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(IconClose, { size: 20, color: textStyle.color }) })
32628
32696
  ] }),
32629
32697
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native16.ScrollView, { style: styles14.content, keyboardShouldPersistTaps: "handled", children: [
32630
32698
  quote ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: [styles14.quote, textStyle], selectable: true, children: quote }) : null,
@@ -32717,10 +32785,17 @@ var BottomBar = ({
32717
32785
  documentType,
32718
32786
  onOpenInfo,
32719
32787
  onOpenSettings,
32720
- onOpenDestination
32788
+ onOpenDestination,
32789
+ onTurnPage,
32790
+ onNavigateToPage,
32791
+ onOpenPages
32721
32792
  }) => {
32722
32793
  const {
32723
32794
  activeMobileDestination,
32795
+ viewMode,
32796
+ comicLayoutMode,
32797
+ currentPage,
32798
+ pageCount,
32724
32799
  mobileDockVisible,
32725
32800
  setDocumentState,
32726
32801
  uiTheme,
@@ -32757,6 +32832,15 @@ var BottomBar = ({
32757
32832
  activeMobileDestination,
32758
32833
  toolDockOpen
32759
32834
  });
32835
+ const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : viewMode === "single");
32836
+ if (paginated) {
32837
+ layout.leftSlots.push(...layout.rightSlots.filter((slot) => slot.key === "search"));
32838
+ layout.rightSlots = [];
32839
+ }
32840
+ const turnPage = (direction) => {
32841
+ if (onTurnPage) onTurnPage(direction);
32842
+ else onNavigateToPage?.(currentPage + direction);
32843
+ };
32760
32844
  const slotMeta = {
32761
32845
  annotate: {
32762
32846
  label: t.tools,
@@ -32882,7 +32966,15 @@ var BottomBar = ({
32882
32966
  isDark && styles15.islandDark
32883
32967
  ],
32884
32968
  testID: "papyrus-floating-bottom-dock",
32885
- children: layout.rightSlots.map((slot) => {
32969
+ children: paginated ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
32970
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "P\xE1gina anterior" : "Previous page", disabled: !dockVisible || !onTurnPage && currentPage <= 1, onPress: () => turnPage(-1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
32971
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Ir para p\xE1gina" : "Go to page", onPress: onOpenPages, style: [styles15.iconOnlyItem, { minWidth: 56 }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native17.Text, { style: { color: iconColor(false), fontWeight: "700", fontSize: 13, lineHeight: 18, includeFontPadding: false }, children: [
32972
+ currentPage,
32973
+ "/",
32974
+ pageCount
32975
+ ] }) }),
32976
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Pr\xF3xima p\xE1gina" : "Next page", disabled: !dockVisible || !onTurnPage && currentPage >= pageCount, onPress: () => turnPage(1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
32977
+ ] }) : layout.rightSlots.map((slot) => {
32886
32978
  const meta = slotMeta[slot.key];
32887
32979
  const Icon = meta.icon;
32888
32980
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
@@ -32945,8 +33037,9 @@ var styles15 = import_react_native17.StyleSheet.create({
32945
33037
  island: {
32946
33038
  flexDirection: "row",
32947
33039
  alignItems: "center",
32948
- paddingVertical: 8,
32949
- paddingHorizontal: 10,
33040
+ height: MOBILE_CHROME_METRICS.bottomBarVisualHeight,
33041
+ paddingVertical: 0,
33042
+ paddingHorizontal: 6,
32950
33043
  backgroundColor: "rgba(255,255,255,0.9)",
32951
33044
  borderWidth: 1,
32952
33045
  borderColor: "rgba(255,255,255,0.72)",
@@ -32972,6 +33065,8 @@ var styles15 = import_react_native17.StyleSheet.create({
32972
33065
  borderColor: "rgba(71,85,105,0.48)"
32973
33066
  },
32974
33067
  iconOnlyItem: {
33068
+ minWidth: 44,
33069
+ height: 44,
32975
33070
  alignItems: "center",
32976
33071
  justifyContent: "center",
32977
33072
  paddingHorizontal: MOBILE_CHROME_METRICS.bottomBarItemPaddingHorizontal,
@@ -33048,7 +33143,8 @@ var SettingsSheet = ({
33048
33143
  engine,
33049
33144
  visible,
33050
33145
  onClose,
33051
- documentType = "pdf"
33146
+ documentType = "pdf",
33147
+ onOpenInfo
33052
33148
  }) => {
33053
33149
  const {
33054
33150
  viewMode,
@@ -33113,6 +33209,7 @@ var SettingsSheet = ({
33113
33209
  contentContainerStyle: styles16.sheetContent,
33114
33210
  showsVerticalScrollIndicator: false,
33115
33211
  children: [
33212
+ onOpenInfo ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native18.Pressable, { accessibilityRole: "button", onPress: onOpenInfo, style: { minHeight: 44, justifyContent: "center", marginBottom: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native18.Text, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.info }) }) : null,
33116
33213
  (documentType === "text" || documentType === "epub") && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native18.View, { style: styles16.section, children: [
33117
33214
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native18.Text, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: locale === "pt-BR" ? "Tamanho da fonte" : "Font size" }),
33118
33215
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native18.View, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
@@ -34218,9 +34315,11 @@ var import_jsx_runtime25 = require("react/jsx-runtime");
34218
34315
  var clampPercent = (value) => Math.max(0, Math.min(100, Math.round(value)));
34219
34316
  function ProgressPill({
34220
34317
  documentType,
34318
+ navigationInDock = false,
34221
34319
  onPress,
34222
34320
  onOpenPageJump,
34223
34321
  onNavigateToPage,
34322
+ onTurnPage,
34224
34323
  onScrubbingChange
34225
34324
  }) {
34226
34325
  const {
@@ -34358,14 +34457,15 @@ function ProgressPill({
34358
34457
  }
34359
34458
  const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : viewMode;
34360
34459
  const pillMode = resolveProgressPillMode(progressViewMode, currentPage, pageCount);
34460
+ if (pillMode.kind === "navigation" && navigationInDock) return null;
34361
34461
  if (pillMode.kind === "navigation") {
34362
- const previousDisabled = pillMode.previousPage === null || !onNavigateToPage;
34363
- const nextDisabled = pillMode.nextPage === null || !onNavigateToPage;
34462
+ const previousDisabled = !onTurnPage && (pillMode.previousPage === null || !onNavigateToPage);
34463
+ const nextDisabled = !onTurnPage && (pillMode.nextPage === null || !onNavigateToPage);
34364
34464
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
34365
34465
  import_react_native23.View,
34366
34466
  {
34367
34467
  pointerEvents: "box-none",
34368
- style: [styles21.frame, styles21.singleFrame, { top: offsets.progress, right: offsets.right }],
34468
+ style: [{ position: "absolute", zIndex: 18, bottom: offsets.bottom + MOBILE_CHROME_METRICS.bottomBarVisualHeight + 12, left: offsets.left, right: offsets.right, alignItems: "center" }],
34369
34469
  children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native23.View, { style: [styles21.singlePill, isDark && styles21.pillDark], children: [
34370
34470
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
34371
34471
  import_react_native23.Pressable,
@@ -34374,7 +34474,7 @@ function ProgressPill({
34374
34474
  accessibilityLabel: t.previousPage,
34375
34475
  accessibilityState: { disabled: previousDisabled },
34376
34476
  disabled: previousDisabled,
34377
- onPress: () => pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34477
+ onPress: () => onTurnPage ? onTurnPage(-1) : pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34378
34478
  style: styles21.pageArrowHit,
34379
34479
  testID: "papyrus-progress-page-previous",
34380
34480
  children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native23.Text, { style: [styles21.pageArrow, isDark && styles21.labelDark, previousDisabled && styles21.pageArrowDisabled], children: "\u2039" })
@@ -34402,7 +34502,7 @@ function ProgressPill({
34402
34502
  accessibilityLabel: t.nextPage,
34403
34503
  accessibilityState: { disabled: nextDisabled },
34404
34504
  disabled: nextDisabled,
34405
- onPress: () => pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34505
+ onPress: () => onTurnPage ? onTurnPage(1) : pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34406
34506
  style: styles21.pageArrowHit,
34407
34507
  testID: "papyrus-progress-page-next",
34408
34508
  children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native23.Text, { style: [styles21.pageArrow, isDark && styles21.labelDark, nextDisabled && styles21.pageArrowDisabled], children: "\u203A" })
@@ -35281,13 +35381,7 @@ function ReadingShell({
35281
35381
  {
35282
35382
  engine,
35283
35383
  title,
35284
- onOpenOverflow: () => {
35285
- closeMobileDestination();
35286
- setInfoOpen(false);
35287
- setActionsOpen(false);
35288
- setSettingsOpen(false);
35289
- setOverflowOpen(true);
35290
- },
35384
+ onOpenSettings: () => openDestination("display"),
35291
35385
  onOpenPageJump: () => setPageJumpOpen(true),
35292
35386
  showPageNavigationControls: false
35293
35387
  }
@@ -35303,7 +35397,13 @@ function ReadingShell({
35303
35397
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35304
35398
  ProgressPill,
35305
35399
  {
35400
+ navigationInDock: true,
35306
35401
  documentType,
35402
+ onTurnPage: documentType === "epub" ? (direction) => {
35403
+ const paginatedEngine = engine;
35404
+ void paginatedEngine.turnEpubPage?.(direction).catch(() => {
35405
+ });
35406
+ } : void 0,
35307
35407
  onNavigateToPage: navigateToPage,
35308
35408
  onPress: () => openDestination(
35309
35409
  documentType === "pdf" ? "pages" : documentType === "epub" ? "contents" : "progress"
@@ -35315,6 +35415,12 @@ function ReadingShell({
35315
35415
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35316
35416
  BottomBar_default,
35317
35417
  {
35418
+ onNavigateToPage: navigateToPage,
35419
+ onOpenPages: () => setPageJumpOpen(true),
35420
+ onTurnPage: documentType === "epub" ? (direction) => {
35421
+ const paginatedEngine = engine;
35422
+ void paginatedEngine.turnEpubPage?.(direction).catch((error) => console.warn("[Papyrus] page navigation failed", error));
35423
+ } : void 0,
35318
35424
  documentType,
35319
35425
  onOpenDestination: openDestination,
35320
35426
  onOpenInfo: () => openDestination("info"),
@@ -35394,6 +35500,7 @@ function ReadingShell({
35394
35500
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35395
35501
  SettingsSheet_default,
35396
35502
  {
35503
+ onOpenInfo: () => openDestination("info"),
35397
35504
  engine,
35398
35505
  documentType,
35399
35506
  visible: settingsOpen,