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

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.mjs CHANGED
@@ -20512,6 +20512,42 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20512
20512
  <!-- @papyrus-comic-runtime:end -->
20513
20513
  <script>
20514
20514
  (function () {
20515
+ /* @papyrus-epub-reader:start */
20516
+ (function(root){
20517
+ function mode(value){return value==='chapter-scroll'?'chapter-scroll':'paged';}
20518
+ function validCfi(value){return typeof value==='string' && value.length<=4096 && /^epubcfi\\([^\\n<>]+\\)$/.test(value);}
20519
+ function options(value){return {manager:'default',flow:mode(value)==='paged'?'paginated':'scrolled-doc',spread:'none',width:'100%',height:'100%',allowScriptedContent:false};}
20520
+ function gesture(start,end,state){
20521
+ if(!start || !end || state.selected || state.interactive || state.multitouch)return null;
20522
+ var dx=end.x-start.x,dy=end.y-start.y,elapsed=end.time-start.time;
20523
+ if(state.mode==='paged' && Math.abs(dx)>=48 && Math.abs(dx)>Math.abs(dy)*1.5 && elapsed>=0 && elapsed<1500)return (dx<0)!==Boolean(state.rtl)?'next':'prev';
20524
+ if(elapsed>=0 && elapsed<450 && Math.hypot(dx,dy)<=12)return 'tap';
20525
+ return null;
20526
+ }
20527
+ function location(raw,count,readingMode){
20528
+ var start=raw && raw.start;if(!start || !validCfi(start.cfi))return null;
20529
+ var displayed=start.displayed||{},chapter=Math.max(1,(Number(start.index)||0)+1);
20530
+ var visualPage=mode(readingMode)==='paged' && Number.isFinite(displayed.page)?displayed.page:null;
20531
+ var total=mode(readingMode)==='paged' && Number.isFinite(displayed.total)?displayed.total:null;
20532
+ var fraction=total?Math.max(0,(visualPage-1)/total):0;
20533
+ return {version:1,cfi:start.cfi,href:start.href||'',chapter:chapter,chapterCount:count,visualPage:visualPage,visualPageCount:total,progress:Math.min(1,Math.max(0,(chapter-1+fraction)/Math.max(1,count))),mode:mode(readingMode),atStart:Boolean(raw.atStart),atEnd:Boolean(raw.atEnd)};
20534
+ }
20535
+ function install(contents,config){
20536
+ var doc=contents.document,win=contents.window,start=null,blocked=false;
20537
+ function point(e){var t=e.changedTouches&&e.changedTouches[0]||e.touches&&e.touches[0];return t?{x:t.clientX,y:t.clientY,time:Date.now()}:null;}
20538
+ function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
20539
+ function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
20540
+ function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
20541
+ function move(e){if(e.touches.length!==1)blocked=true;}
20542
+ function end(e){var action=gesture(start,point(e),{mode:config.mode(),rtl:config.rtl(),selected:selected(),interactive:blocked||interactive(e.target)||Boolean(config.annotationHit && config.annotationHit(point(e))),multitouch:blocked});start=null;if(!config.current())return;if(action==='tap')config.tap();else if(action)config.turn(action==='next'?1:-1);}
20543
+ function cancel(){start=null;blocked=true;}
20544
+ doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});
20545
+ return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);};
20546
+ }
20547
+ root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,install:install};
20548
+ })(typeof window==='undefined'?globalThis:window);
20549
+
20550
+ /* @papyrus-epub-reader:end */
20515
20551
  /* @papyrus-epub-annotations:start */
20516
20552
  (function (root, factory) {
20517
20553
  if (typeof module === 'object' && module.exports) module.exports = factory();
@@ -20590,6 +20626,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20590
20626
  var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
20591
20627
  var style = annotation.markupStyle || annotation.type;
20592
20628
  var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
20629
+ if(style === 'highlight')opacity=Math.min(0.35,opacity);
20593
20630
  rects.forEach(function(rect) {
20594
20631
  var mark = doc.createElement('div');
20595
20632
  var bodyRect=doc.body.getBoundingClientRect();
@@ -20602,8 +20639,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20602
20639
  if (hasNote) {
20603
20640
  var last = rects[rects.length-1], button = doc.createElement('button');
20604
20641
  button.textContent = '\u25CF'; button.setAttribute('aria-label',options.labels().comment || '');
20605
- button.style.cssText = 'position:absolute;pointer-events:auto;border:0;background:transparent;color:'+color+';width:44px;height:44px;left:'+Math.max(0,Math.min(doc.documentElement.clientWidth-44,last.right-doc.body.getBoundingClientRect().left))+'px;top:'+(Math.floor(last.top/44)*44-doc.body.getBoundingClientRect().top)+'px';
20606
- var key = Math.floor(last.top/44);
20642
+ var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
20643
+ var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
20644
+ button.style.cssText = 'position:absolute;pointer-events:auto;border:0;background:transparent;color:'+color+';width:44px;height:44px;left:'+((column+1)*pageWidth-44)+'px;top:'+(Math.floor(last.top/44)*44-doc.body.getBoundingClientRect().top)+'px';
20645
+ var key = column+":"+Math.floor(last.top/44);
20607
20646
  var neighbors=noteGroups.get(key);
20608
20647
  if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
20609
20648
  neighbors.ids.push(annotation.id);
@@ -20624,10 +20663,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20624
20663
  doc.addEventListener('click',tapMarkup);
20625
20664
  var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
20626
20665
  if (observer) observer.observe(doc.body);
20627
- win.addEventListener('resize',schedule); doc.addEventListener('load',schedule,true);
20666
+ win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
20628
20667
  if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
20629
20668
  schedule();
20630
- return {schedule:schedule, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
20669
+ return {schedule:schedule, hit:function(x,y){return hitRegions.some(function(item){return item.rects.some(function(r){return x>=r.left && x<=r.right && y>=r.top && y<=r.bottom;});});}, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);win.removeEventListener('scroll',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
20631
20670
  }
20632
20671
  return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
20633
20672
  });
@@ -21708,26 +21747,55 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21708
21747
  pageCount,
21709
21748
  });
21710
21749
 
21750
+ if (book.locations?.generate) {
21751
+ const activeBook=book;
21752
+ activeBook.locations.generate(150).then(() => {
21753
+ if (isCurrentLoad() && activeBook===book && epubLocation) {
21754
+ epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
21755
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21756
+ }
21757
+ }).catch(() => {});
21758
+ }
21759
+ return renderEpubRendition(loadId,generation,null);
21760
+ };
21761
+
21762
+ const renderEpubRendition = async (loadId,generation,target) => {
21763
+ const diagnosticPayload={loadId};
21764
+ const isCurrentLoad=()=>generation===epubLoadGeneration;
21765
+ if(epubInteractionCleanup)epubInteractionCleanup();
21766
+ if(rendition)rendition.destroy();
21711
21767
  clearViewer();
21712
- rendition = book.renderTo(viewer, {
21713
- manager: 'continuous',
21714
- allowScriptedContent: false,
21715
- width: '100%',
21716
- height: '100%',
21717
- flow: 'scrolled-continuous',
21718
- spread: 'none',
21719
- });
21768
+ rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
21720
21769
  sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
21721
21770
 
21722
21771
  if (rendition && rendition.hooks && rendition.hooks.content) {
21723
21772
  const session = documentSessionId;
21724
21773
  const activeRendition = rendition;
21725
21774
  rendition.hooks.content.register((contents) => {
21775
+ const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
21776
+ mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
21777
+ rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
21778
+ blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
21779
+ annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
21780
+ current: () => session === documentSessionId && activeRendition === rendition,
21781
+ tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
21782
+ turn: direction => {
21783
+ epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
21784
+ if(session !== documentSessionId || activeRendition !== rendition)return;
21785
+ return direction<0?activeRendition.prev():activeRendition.next();
21786
+ });
21787
+ epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
21788
+ },
21789
+ });
21790
+ const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
21791
+ epubSelectionCleanups.add(gestureCleanup);
21792
+ contents.__papyrusGestureCleanup=gestureCleanup;
21726
21793
  const href = spineItems[contents.sectionIndex]?.href;
21727
21794
  if (href && window.PapyrusEpubAnnotations) {
21728
21795
  const renderer = window.PapyrusEpubAnnotations.install(contents, {
21729
21796
  href, get documentId() { return annotationDocumentId; },
21730
21797
  isCurrent: () => session === documentSessionId && activeRendition === rendition,
21798
+ pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
21731
21799
  annotations: () => epubAnnotations, labels: () => annotationLabels,
21732
21800
  onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
21733
21801
  });
@@ -21746,8 +21814,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21746
21814
  typeof selectionWindow.getSelection === 'function'
21747
21815
  ) {
21748
21816
  let selectionTimer = null;
21749
- let lastSelectionKey = '';
21750
- let lastSelectionAt = 0;
21817
+
21751
21818
  const reportSelection = () => {
21752
21819
  selectionTimer = null;
21753
21820
  if (session !== documentSessionId || activeRendition !== rendition) return;
@@ -21762,11 +21829,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21762
21829
  try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
21763
21830
  const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
21764
21831
  if (!anchor) return;
21765
- const key = anchor.cfiRange + ':' + anchor.quote;
21766
- const now = Date.now();
21767
- if (key === lastSelectionKey && now - lastSelectionAt < 750) return;
21768
- lastSelectionKey = key;
21769
- lastSelectionAt = now;
21832
+ if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21770
21833
  const payload = {documentSessionId: session, text: anchor.quote,
21771
21834
  pageIndex: contents.sectionIndex + 1, anchor};
21772
21835
  nativeMenuSelection = {contents, payload};
@@ -21781,6 +21844,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21781
21844
  // The content document still emits selectionchange, so resolve its
21782
21845
  // live Range to a CFI before the native menu action can fire.
21783
21846
  if (text) reportSelection();
21847
+ else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
21784
21848
  };
21785
21849
  selectionDocument.addEventListener('selectionchange', handleSelectionChange);
21786
21850
  const selectionCleanup = () => {
@@ -21803,6 +21867,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21803
21867
  typeof rendition.hooks.unloaded.register === 'function'
21804
21868
  ) {
21805
21869
  rendition.hooks.unloaded.register((view) => {
21870
+ view?.contents?.__papyrusGestureCleanup?.();
21806
21871
  const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
21807
21872
  if (typeof cleanup === 'function') cleanup();
21808
21873
  const renderer = epubAnnotationRenderers.get(view?.contents);
@@ -21818,21 +21883,27 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21818
21883
  if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21819
21884
  const href = spineItems[contents.sectionIndex]?.href;
21820
21885
  const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
21821
- if (!anchor) return;
21886
+ if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21822
21887
  epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
21823
21888
  const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
21824
21889
  nativeMenuSelection = {contents, payload};
21825
21890
  sendEvent('EPUB_TEXT_SELECTED', payload);
21826
21891
  });
21827
- ['rendered','resized','layout'].forEach(name => rendition.on(name, () => {
21892
+ ['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
21828
21893
  if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
21829
21894
  }));
21830
21895
  rendition.on('relocated', (location) => {
21896
+ if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21831
21897
  const start = location && location.start;
21832
21898
  let index = start && Number.isInteger(start.index) ? start.index : -1;
21833
21899
  if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
21834
21900
  if (index < 0 || index >= spineItems.length) return;
21835
21901
  epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
21902
+ epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll');
21903
+ if(epubLocation){
21904
+ if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
21905
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21906
+ }
21836
21907
  const nextPage = index + 1;
21837
21908
  if (nextPage === currentPage) return;
21838
21909
  currentPage = nextPage;
@@ -21840,9 +21911,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21840
21911
  });
21841
21912
  }
21842
21913
 
21914
+ applyEpubZoom();
21843
21915
  sendEpubDiagnostic('epub.display.start', diagnosticPayload);
21844
21916
  await withEpubStageTimeout(
21845
- displayEpubPage(0),
21917
+ rendition.display(target || spineItems[0]?.href),
21846
21918
  'rendition.display',
21847
21919
  diagnosticPayload,
21848
21920
  );
@@ -21854,7 +21926,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21854
21926
  typeof rendition.manager.on === 'function' &&
21855
21927
  typeof rendition.on === 'function'
21856
21928
  ) {
21857
- let touchStart = null;
21858
21929
  let lastScrollOffset = -1;
21859
21930
  const manager = rendition.manager;
21860
21931
  epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
@@ -21929,48 +22000,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21929
22000
  return result;
21930
22001
  };
21931
22002
  }
21932
- const getTouchPoint = (event) => {
21933
- const touch =
21934
- (event && event.changedTouches && event.changedTouches[0]) ||
21935
- (event && event.touches && event.touches[0]);
21936
- if (!touch) return null;
21937
- const x = Number(touch.screenX ?? touch.clientX);
21938
- const y = Number(touch.screenY ?? touch.clientY);
21939
- return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
21940
- };
21941
- const handleScroll = (event) => {
22003
+ const handleScroll = event => {
21942
22004
  const offsetY = Math.max(0, Number(event && event.top) || 0);
21943
22005
  epubScrollDiagnostics && epubScrollDiagnostics.scroll(event);
21944
- if (Math.abs(offsetY - lastScrollOffset) < 1) return;
21945
- lastScrollOffset = offsetY;
21946
- sendEvent('VIEWER_SCROLL', { offsetY });
21947
- };
21948
- const handleTouchStart = (event) => {
21949
- touchStart = getTouchPoint(event);
21950
- epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
21951
- };
21952
- const handleTouchMove = (event) => {
21953
- epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
21954
- };
21955
- const handleTouchEnd = (event) => {
21956
- const end = getTouchPoint(event);
21957
- const start = touchStart;
21958
- touchStart = null;
21959
- const selectedText = event?.target?.ownerDocument?.defaultView?.getSelection?.()?.toString().trim() || '';
21960
- if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
21961
- sendEvent('VIEWER_TAP', {});
21962
- }
21963
- epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
22006
+ if (Math.abs(offsetY-lastScrollOffset)<1) return;
22007
+ lastScrollOffset=offsetY;
22008
+ sendEvent('VIEWER_SCROLL',{offsetY});
21964
22009
  };
21965
-
21966
22010
  manager.on('scroll', handleScroll);
21967
22011
  const handleScrolled = (event) => {
21968
22012
  epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
21969
22013
  };
21970
22014
  manager.on('scrolled', handleScrolled);
21971
- rendition.on('touchstart', handleTouchStart);
21972
- rendition.on('touchmove', handleTouchMove);
21973
- rendition.on('touchend', handleTouchEnd);
22015
+
21974
22016
  epubInteractionCleanup = () => {
21975
22017
  epubSelectionCleanups.forEach((cleanup) => cleanup());
21976
22018
  epubSelectionCleanups.clear();
@@ -21979,16 +22021,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21979
22021
  if (originalEnqueue) queue.enqueue = originalEnqueue;
21980
22022
  if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
21981
22023
  if (typeof manager.off === 'function') manager.off('scrolled', handleScrolled);
21982
- if (typeof rendition.off === 'function') {
21983
- rendition.off('touchstart', handleTouchStart);
21984
- rendition.off('touchmove', handleTouchMove);
21985
- rendition.off('touchend', handleTouchEnd);
21986
- }
21987
22024
  epubScrollDiagnostics = null;
21988
22025
  };
21989
22026
  }
21990
- applyEpubZoom();
21991
-
21992
22027
  const outline = await withEpubStageTimeout(
21993
22028
  buildOutline(),
21994
22029
  'outline',
@@ -22002,6 +22037,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22002
22037
  return { pageCount, outline };
22003
22038
  };
22004
22039
 
22040
+ let epubNavigationQueue = Promise.resolve();
22041
+ let epubNavigationRequest = 0;
22005
22042
  const displayEpubPage = async (pageIndex) => {
22006
22043
  if (!rendition) return;
22007
22044
  const item = spineItems[pageIndex];
@@ -22011,9 +22048,18 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22011
22048
  target,
22012
22049
  pageIndex,
22013
22050
  });
22014
- await rendition.display(target);
22015
- currentPage = pageIndex + 1;
22016
- sendState();
22051
+ const activeRendition = rendition;
22052
+ const session = documentSessionId;
22053
+ const request = ++epubNavigationRequest;
22054
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22055
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22056
+ await activeRendition.display(target);
22057
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22058
+ currentPage = pageIndex + 1;
22059
+ sendState();
22060
+ });
22061
+ epubNavigationQueue = navigation;
22062
+ await navigation;
22017
22063
  };
22018
22064
 
22019
22065
  const getTextContent = async (pageIndex) => {
@@ -22115,6 +22161,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22115
22161
  };
22116
22162
 
22117
22163
  let nativeMenuSelection = null;
22164
+ let epubViewMode = "single";
22165
+ let epubLocation = null;
22118
22166
 
22119
22167
  const handleCommand = async (message) => {
22120
22168
  const { id, kind, payload } = message;
@@ -22127,6 +22175,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22127
22175
  epubAnnotations = [];
22128
22176
  annotationDocumentId = undefined;
22129
22177
  zoom = 1.0;
22178
+ epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
22179
+ epubLocation = null;
22180
+ nativeMenuSelection = null;
22181
+ epubNavigationRequest += 1;
22182
+ epubNavigationQueue = Promise.resolve();
22130
22183
 
22131
22184
  if (currentType === 'text') {
22132
22185
  const result = await loadText(
@@ -22181,17 +22234,23 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22181
22234
  epubAnnotationRenderers.forEach(renderer => renderer.schedule());
22182
22235
  } else {
22183
22236
  const annotation = epubAnnotations.find(a => a.id === payload.annotationId);
22184
- if (!annotation) throw new Error('Annotation not available');
22237
+ if (!annotation || (annotation.anchor.documentId && annotation.anchor.documentId !== annotationDocumentId)) throw new Error('Annotation not available for this document');
22185
22238
  // Navigation uses the CFI, never a synthetic percentage/page rectangle.
22186
22239
  const navigationSession = documentSessionId;
22187
22240
  const activeRendition = rendition;
22188
22241
  // Open the confirmed chapter first, resolve its quote, then navigate its actual range.
22189
- await activeRendition.display(annotation.anchor.href);
22190
- if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22191
- const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
22192
- const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
22193
- if(!range)throw new Error('EPUB anchor unresolved');
22194
- await activeRendition.display(contents.cfiFromRange(range));
22242
+ epubNavigationRequest += 1;
22243
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22244
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22245
+ await activeRendition.display(annotation.anchor.href);
22246
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22247
+ const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
22248
+ const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
22249
+ if(!range)throw new Error('EPUB anchor unresolved');
22250
+ await activeRendition.display(contents.cfiFromRange(range));
22251
+ });
22252
+ epubNavigationQueue = navigation;
22253
+ await navigation;
22195
22254
  }
22196
22255
  sendResponse(id,true,null); return;
22197
22256
  }
@@ -22218,12 +22277,54 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22218
22277
  return;
22219
22278
  }
22220
22279
 
22280
+ if (kind === 'epub-turn-page') {
22281
+ if (epubViewMode !== 'single') {sendResponse(id,true,null); return;}
22282
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB navigation');
22283
+ const active = rendition;
22284
+ epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22285
+ if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22286
+ return payload.direction < 0 ? active.prev() : active.next();
22287
+ });
22288
+ await epubNavigationQueue;
22289
+ sendResponse(id,true,null); return;
22290
+ }
22291
+
22292
+ if (kind === 'set-epub-view-mode') {
22293
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
22294
+ const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
22295
+ {
22296
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22297
+ if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
22298
+ const target=epubLocation?.cfi;
22299
+ epubViewMode=next;
22300
+ await renderEpubRendition('layout',epubLoadGeneration,target);
22301
+ });
22302
+ await epubNavigationQueue;
22303
+ }
22304
+ sendResponse(id,true,null);return;
22305
+ }
22306
+ if(kind === 'epub-go-to-location'){
22307
+ if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
22308
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>payload.documentSessionId===documentSessionId?rendition.display(payload.cfi):undefined);
22309
+ await epubNavigationQueue;sendResponse(id,true,null);return;
22310
+ }
22311
+
22221
22312
  if (kind === 'set-zoom') {
22222
- zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
22223
- applyZoom();
22224
- sendState();
22225
- sendResponse(id, true, { zoom });
22226
- return;
22313
+ const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
22314
+ if(currentType === 'epub') {
22315
+ const session=documentSessionId;
22316
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22317
+ if(session!==documentSessionId)return;
22318
+ const active=rendition;
22319
+ const cfi=epubLocation?.cfi;
22320
+ zoom=requestedZoom;applyEpubZoom();
22321
+ // Let the content CSS update before redisplaying the logical anchor.
22322
+ await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
22323
+ if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
22324
+ });
22325
+ await epubNavigationQueue;
22326
+ } else {zoom=requestedZoom;applyZoom();}
22327
+ sendState();sendResponse(id,true,{zoom});return;
22227
22328
  }
22228
22329
 
22229
22330
  if (kind === 'set-rotation') {
@@ -23399,6 +23500,7 @@ var IconToolStrikeout = ({
23399
23500
  ),
23400
23501
  /* @__PURE__ */ jsx2(Rect, { x: "10.9", y: "17.1", width: "14.2", height: "2.4", rx: "1.2", fill: color })
23401
23502
  ] });
23503
+ var IconStrikeout = ({ size = 22, color = defaultColor, strokeWidth = 1.8 }) => /* @__PURE__ */ jsx2(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx2(Path, { d: "M17 5c-1-1-3-2-5-2-3 0-5 2-5 4 0 2 2 3 5 4M17 15c0 2-2 4-5 4-2 0-4-1-5-2M4 12h16", stroke: color, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }) });
23402
23504
  var IconCopy = ({
23403
23505
  size = 20,
23404
23506
  color = defaultColor,
@@ -23463,6 +23565,39 @@ var IconToolNote = ({
23463
23565
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "14.8", x2: "21.6", y2: "14.8", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" }),
23464
23566
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "18.2", x2: "19.2", y2: "18.2", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" })
23465
23567
  ] });
23568
+ var IconHighlight = ({
23569
+ size = 24,
23570
+ color = "#fbbf24"
23571
+ }) => /* @__PURE__ */ jsxs(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
23572
+ /* @__PURE__ */ jsx2(
23573
+ Path,
23574
+ {
23575
+ d: "M4 15h16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3Z",
23576
+ fill: color,
23577
+ opacity: "0.85"
23578
+ }
23579
+ ),
23580
+ /* @__PURE__ */ jsx2(
23581
+ Path,
23582
+ {
23583
+ d: "M6 5h12v10H6V5Z",
23584
+ stroke: color,
23585
+ strokeWidth: "2",
23586
+ strokeLinecap: "round",
23587
+ strokeLinejoin: "round",
23588
+ fill: "none"
23589
+ }
23590
+ ),
23591
+ /* @__PURE__ */ jsx2(
23592
+ Path,
23593
+ {
23594
+ d: "M8 8h8M8 11h5",
23595
+ stroke: color,
23596
+ strokeWidth: "2",
23597
+ strokeLinecap: "round"
23598
+ }
23599
+ )
23600
+ ] });
23466
23601
  var IconUnderline = ({
23467
23602
  size = 24,
23468
23603
  color = "#60a5fa",
@@ -25673,6 +25808,39 @@ var styles = StyleSheet.create({
25673
25808
  var arePageRendererPropsEqual = (previous, next) => previous.documentId === next.documentId && previous.engine === next.engine && previous.pageIndex === next.pageIndex && previous.scale === next.scale && previous.PageViewComponent === next.PageViewComponent && previous.availableWidth === next.availableWidth && previous.maxPageWidth === next.maxPageWidth && previous.maxPageHeight === next.maxPageHeight && previous.pageViewportWidth === next.pageViewportWidth && previous.horizontalPadding === next.horizontalPadding && previous.spacing === next.spacing && previous.onSelectionDragActiveChange === next.onSelectionDragActiveChange && previous.gestureScrollLockActive === next.gestureScrollLockActive && previous.lastPinchEndedAt === next.lastPinchEndedAt && previous.requestSelectionVerticalAutoscroll === next.requestSelectionVerticalAutoscroll;
25674
25809
  var PageRenderer_default = memo(PageRenderer, arePageRendererPropsEqual);
25675
25810
 
25811
+ // components/PapyrusSafeArea.tsx
25812
+ import React3, { useContext as useContext2 } from "react";
25813
+ import {
25814
+ SafeAreaInsetsContext,
25815
+ SafeAreaProvider
25816
+ } from "react-native-safe-area-context";
25817
+ import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
25818
+ var papyrusSafeAreaContext = SafeAreaInsetsContext;
25819
+ var ZERO_SAFE_AREA_INSETS = {
25820
+ top: 0,
25821
+ bottom: 0,
25822
+ left: 0,
25823
+ right: 0
25824
+ };
25825
+ var usePapyrusSafeAreaInsets = () => useContext2(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
25826
+ function PapyrusSafeAreaBoundary({
25827
+ children
25828
+ }) {
25829
+ const insets = useContext2(papyrusSafeAreaContext);
25830
+ if (insets) return /* @__PURE__ */ jsx4(Fragment, { children });
25831
+ return React3.createElement(SafeAreaProvider, null, children);
25832
+ }
25833
+
25834
+ // components/epubReadingLocation.ts
25835
+ function parseEpubReadingLocation(raw) {
25836
+ if (!raw || typeof raw !== "object") return null;
25837
+ const p = raw;
25838
+ if (p.version !== 1 || typeof p.cfi !== "string" || p.cfi.length > 4096 || !/^epubcfi\([^\n<>]+\)$/.test(p.cfi) || typeof p.href !== "string" || !Number.isSafeInteger(p.chapter) || p.chapter < 1 || !Number.isSafeInteger(p.chapterCount) || p.chapterCount < p.chapter || !Number.isFinite(p.progress) || p.progress < 0 || p.progress > 1 || typeof p.atStart !== "boolean" || typeof p.atEnd !== "boolean") return null;
25839
+ if (p.mode === "chapter-scroll") return p.visualPage === null && p.visualPageCount === null ? p : null;
25840
+ if (p.mode !== "paged" || !Number.isSafeInteger(p.visualPage) || (p.visualPage ?? 0) < 1 || !Number.isSafeInteger(p.visualPageCount) || (p.visualPageCount ?? 0) < (p.visualPage ?? 0)) return null;
25841
+ return p;
25842
+ }
25843
+
25676
25844
  // components/WebViewViewer.tsx
25677
25845
  import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
25678
25846
  import { Image, StyleSheet as StyleSheet2, View as View2, Alert } from "react-native";
@@ -25742,7 +25910,7 @@ function parseEpubAnnotationEvent(raw, session, documentId) {
25742
25910
  }
25743
25911
 
25744
25912
  // components/WebViewViewer.tsx
25745
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
25913
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
25746
25914
  var runtimeAsset = require_runtime();
25747
25915
  var resolveRuntimeSource = (asset) => {
25748
25916
  if (typeof asset === "string") {
@@ -25762,6 +25930,7 @@ var resolveRuntimeSource = (asset) => {
25762
25930
  };
25763
25931
  var WebViewViewer = ({
25764
25932
  engine,
25933
+ documentType,
25765
25934
  documentId,
25766
25935
  onDefineSelection,
25767
25936
  defineSelectionMode,
@@ -25770,7 +25939,8 @@ var WebViewViewer = ({
25770
25939
  onTap
25771
25940
  }) => {
25772
25941
  const webViewRef = useRef2(null);
25773
- const { pageTheme, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25942
+ const insets = usePapyrusSafeAreaInsets();
25943
+ const { pageTheme, epubReadingMode, setDocumentState, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25774
25944
  const [selection, setSelection] = useState2(null);
25775
25945
  const t = getStrings(locale);
25776
25946
  const bridgeEngine = engine;
@@ -25851,6 +26021,10 @@ var WebViewViewer = ({
25851
26021
  (note !== void 0 ? beginAnnotationDraft : addAnnotation)(createContextualAnnotation({ id: `annotation-${Date.now()}-${Math.random().toString(36).slice(2)}`, anchor: selected.anchor, pageIndex: selected.pageIndex, style, color: annotationColor, opacity: annotationOpacity, note }));
25852
26022
  setSelection(null);
25853
26023
  };
26024
+ useEffect2(() => {
26025
+ if (!isLoaded) return;
26026
+ webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { epubMode: epubReadingMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26027
+ }, [isLoaded, epubReadingMode, bridgeEngine]);
25854
26028
  const sendSelectionCommand = (key) => {
25855
26029
  webViewRef.current?.postMessage(JSON.stringify({
25856
26030
  type: "epub-selection-action",
@@ -25874,6 +26048,11 @@ var WebViewViewer = ({
25874
26048
  let annotationRaw = raw;
25875
26049
  try {
25876
26050
  const message = JSON.parse(raw);
26051
+ if (message.type === "event" && message.name === "EPUB_LOCATION" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) {
26052
+ const location = parseEpubReadingLocation(message.payload.location);
26053
+ if (location) setDocumentState({ epubLocation: location });
26054
+ }
26055
+ if (message.type === "event" && message.name === "EPUB_CONTENT_TAP" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) onTap?.();
25877
26056
  if (message.type === "event" && message.name === "EPUB_SELECTION_ACTION") {
25878
26057
  action = message.payload?.action;
25879
26058
  annotationRaw = JSON.stringify({ ...message, name: "EPUB_TEXT_SELECTED" });
@@ -25962,8 +26141,8 @@ var WebViewViewer = ({
25962
26141
  maxWidth: resolvedMaxPageWidth,
25963
26142
  alignSelf: "center"
25964
26143
  } : void 0;
25965
- return /* @__PURE__ */ jsxs3(View2, { style: styles2.container, children: [
25966
- /* @__PURE__ */ jsx4(
26144
+ return /* @__PURE__ */ jsxs3(View2, { style: [styles2.container, documentType === "epub" && { paddingTop: insets.top, paddingBottom: insets.bottom }], children: [
26145
+ /* @__PURE__ */ jsx5(
25967
26146
  WebView,
25968
26147
  {
25969
26148
  ref: webViewRef,
@@ -25987,7 +26166,7 @@ var WebViewViewer = ({
25987
26166
  style: [styles2.webview, cappedWebViewStyle]
25988
26167
  }
25989
26168
  ),
25990
- /* @__PURE__ */ jsx4(
26169
+ /* @__PURE__ */ jsx5(
25991
26170
  View2,
25992
26171
  {
25993
26172
  pointerEvents: "none",
@@ -26089,16 +26268,16 @@ function getNearbyPdfNotes(annotations, id) {
26089
26268
  // components/PdfNoteChooser.tsx
26090
26269
  import { FlatList, Modal, Pressable as Pressable2, StyleSheet as StyleSheet3, Text, View as View3 } from "react-native";
26091
26270
  import { getAnnotationNote, getAnnotationQuote } from "@papyrus-sdk/core";
26092
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
26271
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
26093
26272
  function PdfNoteChooser({ notes, title, cancel, onSelect, onClose }) {
26094
- return /* @__PURE__ */ jsx5(Modal, { visible: notes.length > 1, transparent: true, animationType: "none", onRequestClose: onClose, children: /* @__PURE__ */ jsx5(View3, { style: styles3.backdrop, children: /* @__PURE__ */ jsxs4(View3, { style: styles3.sheet, accessibilityViewIsModal: true, children: [
26095
- /* @__PURE__ */ jsx5(Text, { style: styles3.title, children: title }),
26096
- /* @__PURE__ */ jsx5(FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ jsx5(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ jsxs4(Text, { children: [
26273
+ return /* @__PURE__ */ jsx6(Modal, { visible: notes.length > 1, transparent: true, animationType: "none", onRequestClose: onClose, children: /* @__PURE__ */ jsx6(View3, { style: styles3.backdrop, children: /* @__PURE__ */ jsxs4(View3, { style: styles3.sheet, accessibilityViewIsModal: true, children: [
26274
+ /* @__PURE__ */ jsx6(Text, { style: styles3.title, children: title }),
26275
+ /* @__PURE__ */ jsx6(FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ jsx6(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ jsxs4(Text, { children: [
26097
26276
  index + 1,
26098
26277
  ". ",
26099
26278
  getAnnotationNote(item) || getAnnotationQuote(item)
26100
26279
  ] }) }) }),
26101
- /* @__PURE__ */ jsx5(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx5(Text, { children: cancel }) })
26280
+ /* @__PURE__ */ jsx6(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx6(Text, { children: cancel }) })
26102
26281
  ] }) }) });
26103
26282
  }
26104
26283
  var styles3 = StyleSheet3.create({ backdrop: { flex: 1, backgroundColor: "#0008", justifyContent: "center", padding: 24 }, sheet: { backgroundColor: "#fff", borderRadius: 16, padding: 16, maxHeight: "75%" }, title: { fontSize: 18, fontWeight: "600", marginBottom: 12 }, row: { minHeight: 44, padding: 12 } });
@@ -26125,7 +26304,7 @@ var resolvePageTapChromeVisibility = ({
26125
26304
  };
26126
26305
 
26127
26306
  // components/DedicatedAndroidPdfViewer.tsx
26128
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
26307
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
26129
26308
  var TEXT_MARKUP_TOOLS2 = /* @__PURE__ */ new Set(["highlight", "underline", "squiggly", "strikeout"]);
26130
26309
  var MOBILE_CHROME_HIDE_DELTA = 28;
26131
26310
  var MOBILE_CHROME_SHOW_DELTA = 22;
@@ -26269,11 +26448,11 @@ function DedicatedAndroidPdfViewer({
26269
26448
  selectionRef.current = null;
26270
26449
  }, [addAnnotation, beginAnnotationDraft, annotationColor, documentId]);
26271
26450
  return /* @__PURE__ */ jsxs5(View4, { style: styles4.container, children: [
26272
- /* @__PURE__ */ jsx6(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26451
+ /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26273
26452
  setPendingNotes([]);
26274
26453
  setSelectedAnnotation(id);
26275
26454
  } }),
26276
- /* @__PURE__ */ jsx6(
26455
+ /* @__PURE__ */ jsx7(
26277
26456
  PapyrusPdfDocumentView,
26278
26457
  {
26279
26458
  style: [styles4.viewer, cappedViewerStyle],
@@ -26484,7 +26663,7 @@ var resolveNativePdfVisiblePages = (pages) => (pages ?? []).flatMap((page) => {
26484
26663
  });
26485
26664
 
26486
26665
  // components/DedicatedIosPdfViewer.tsx
26487
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
26666
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
26488
26667
  var MOBILE_CHROME_HIDE_DELTA2 = 28;
26489
26668
  var MOBILE_CHROME_SHOW_DELTA2 = 22;
26490
26669
  var MOBILE_CHROME_SHOW_DELAY_MS2 = 180;
@@ -26723,11 +26902,11 @@ function DedicatedIosPdfViewer({
26723
26902
  alignSelf: "center"
26724
26903
  } : void 0;
26725
26904
  return /* @__PURE__ */ jsxs6(View5, { style: styles5.container, children: [
26726
- /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26905
+ /* @__PURE__ */ jsx8(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26727
26906
  setPendingNotes([]);
26728
26907
  setSelectedAnnotation(id);
26729
26908
  } }),
26730
- /* @__PURE__ */ jsx7(
26909
+ /* @__PURE__ */ jsx8(
26731
26910
  PapyrusPdfDocumentView2,
26732
26911
  {
26733
26912
  style: [styles5.viewer, cappedViewerStyle],
@@ -26796,22 +26975,22 @@ function DedicatedIosPdfViewer({
26796
26975
  onInkToolPickerVisibilityChange: handleInkToolPickerVisibilityChange
26797
26976
  }
26798
26977
  ),
26799
- selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx7(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx7(
26978
+ selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx8(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx8(
26800
26979
  Pressable3,
26801
26980
  {
26802
26981
  onPress: defineSelection,
26803
26982
  style: styles5.fallbackButton,
26804
26983
  accessibilityRole: "button",
26805
26984
  accessibilityLabel: t.define,
26806
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.fallbackButtonText, children: t.define })
26985
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.fallbackButtonText, children: t.define })
26807
26986
  }
26808
26987
  ) }),
26809
- fallbackDeleteAnnotation && /* @__PURE__ */ jsx7(
26988
+ fallbackDeleteAnnotation && /* @__PURE__ */ jsx8(
26810
26989
  View5,
26811
26990
  {
26812
26991
  style: styles5.annotationDeleteFallback,
26813
26992
  pointerEvents: "box-none",
26814
- children: /* @__PURE__ */ jsx7(
26993
+ children: /* @__PURE__ */ jsx8(
26815
26994
  Pressable3,
26816
26995
  {
26817
26996
  onPress: () => handleDeleteAnnotation(fallbackDeleteAnnotation.id),
@@ -26819,7 +26998,7 @@ function DedicatedIosPdfViewer({
26819
26998
  accessibilityRole: "button",
26820
26999
  accessibilityLabel: t.deleteAnnotation,
26821
27000
  hitSlop: 8,
26822
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
27001
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
26823
27002
  }
26824
27003
  )
26825
27004
  }
@@ -26882,7 +27061,7 @@ var styles5 = StyleSheet5.create({
26882
27061
  });
26883
27062
 
26884
27063
  // components/NativePdfDocumentViewer.tsx
26885
- import { jsx as jsx8 } from "react/jsx-runtime";
27064
+ import { jsx as jsx9 } from "react/jsx-runtime";
26886
27065
  function NativePdfDocumentViewer({
26887
27066
  engine,
26888
27067
  documentId,
@@ -26895,7 +27074,7 @@ function NativePdfDocumentViewer({
26895
27074
  Platform3.OS
26896
27075
  );
26897
27076
  if (implementation === "android") {
26898
- return /* @__PURE__ */ jsx8(
27077
+ return /* @__PURE__ */ jsx9(
26899
27078
  DedicatedAndroidPdfViewer,
26900
27079
  {
26901
27080
  engine,
@@ -26908,7 +27087,7 @@ function NativePdfDocumentViewer({
26908
27087
  );
26909
27088
  }
26910
27089
  if (implementation === "ios") {
26911
- return /* @__PURE__ */ jsx8(
27090
+ return /* @__PURE__ */ jsx9(
26912
27091
  DedicatedIosPdfViewer,
26913
27092
  {
26914
27093
  engine,
@@ -26964,29 +27143,6 @@ var resolveMobileChromeOffsets = (insets) => ({
26964
27143
  right: MOBILE_CHROME_METRICS.screenPadding + Math.max(0, insets.right)
26965
27144
  });
26966
27145
 
26967
- // components/PapyrusSafeArea.tsx
26968
- import React6, { useContext as useContext2 } from "react";
26969
- import {
26970
- SafeAreaInsetsContext,
26971
- SafeAreaProvider
26972
- } from "react-native-safe-area-context";
26973
- import { Fragment, jsx as jsx9 } from "react/jsx-runtime";
26974
- var papyrusSafeAreaContext = SafeAreaInsetsContext;
26975
- var ZERO_SAFE_AREA_INSETS = {
26976
- top: 0,
26977
- bottom: 0,
26978
- left: 0,
26979
- right: 0
26980
- };
26981
- var usePapyrusSafeAreaInsets = () => useContext2(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
26982
- function PapyrusSafeAreaBoundary({
26983
- children
26984
- }) {
26985
- const insets = useContext2(papyrusSafeAreaContext);
26986
- if (insets) return /* @__PURE__ */ jsx9(Fragment, { children });
26987
- return React6.createElement(SafeAreaProvider, null, children);
26988
- }
26989
-
26990
27146
  // components/NativeTextDocumentViewer.tsx
26991
27147
  import { jsx as jsx10 } from "react/jsx-runtime";
26992
27148
  function NativeTextDocumentViewer({
@@ -27537,6 +27693,7 @@ var scrollViewerListToOffset = (list, offset, animated) => {
27537
27693
  list.scrollToOffset?.({ offset, animated });
27538
27694
  };
27539
27695
  var Viewer = ({
27696
+ documentType,
27540
27697
  documentId,
27541
27698
  engine,
27542
27699
  maxPageWidth,
@@ -29064,14 +29221,8 @@ var Viewer = ({
29064
29221
  },
29065
29222
  [mobilePerf, perfEnabled, scrollPerfSession]
29066
29223
  );
29067
- const handleWebViewScroll = useCallback4(
29068
- (_offsetY) => {
29069
- if (!chromeVisibleRef.current) {
29070
- setMobileChromeVisible(true, "scroll.webview.recover");
29071
- }
29072
- },
29073
- [setMobileChromeVisible]
29074
- );
29224
+ const handleWebViewScroll = useCallback4((_offsetY) => {
29225
+ }, []);
29075
29226
  const handlePageTap = useCallback4(() => {
29076
29227
  const nextVisible = resolvePageTapChromeVisibility({
29077
29228
  chromeVisible: chromeVisibleRef.current,
@@ -29293,6 +29444,7 @@ var Viewer = ({
29293
29444
  return /* @__PURE__ */ jsx12(View8, { style: [styles8.container, isDark && styles8.containerDark], children: /* @__PURE__ */ jsx12(
29294
29445
  WebViewViewer_default,
29295
29446
  {
29447
+ documentType,
29296
29448
  engine,
29297
29449
  documentId,
29298
29450
  onDefineSelection,
@@ -29499,7 +29651,8 @@ import {
29499
29651
  Text as Text5,
29500
29652
  Pressable as Pressable6,
29501
29653
  StyleSheet as StyleSheet11,
29502
- useWindowDimensions as useWindowDimensions4
29654
+ useWindowDimensions as useWindowDimensions4,
29655
+ Platform as Platform6
29503
29656
  } from "react-native";
29504
29657
  import { useViewerStore as useViewerStore9 } from "@papyrus-sdk/core";
29505
29658
  import Animated3, { useAnimatedStyle } from "react-native-reanimated";
@@ -29862,6 +30015,7 @@ var styles9 = StyleSheet9.create({
29862
30015
  // components/PageJumpModal.tsx
29863
30016
  import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
29864
30017
  function PageJumpModal({
30018
+ documentType,
29865
30019
  visible,
29866
30020
  currentPage,
29867
30021
  pageCount,
@@ -29888,8 +30042,8 @@ function PageJumpModal({
29888
30042
  isDark,
29889
30043
  maxHeight: 300,
29890
30044
  showHeader: true,
29891
- title: "Ir para p\xE1gina",
29892
- closeAccessibilityLabel: "Close page jump",
30045
+ title: documentType === "epub" ? "Ir para cap\xEDtulo" : "Ir para p\xE1gina",
30046
+ closeAccessibilityLabel: "Fechar navega\xE7\xE3o",
29893
30047
  sheetStyle: {
29894
30048
  paddingHorizontal: 18,
29895
30049
  paddingBottom: 18,
@@ -29917,7 +30071,7 @@ function PageJumpModal({
29917
30071
  }
29918
30072
  ],
29919
30073
  onSubmitEditing: confirmJump,
29920
- accessibilityLabel: "Page jump input",
30074
+ accessibilityLabel: documentType === "epub" ? "N\xFAmero do cap\xEDtulo" : "N\xFAmero da p\xE1gina",
29921
30075
  testID: "papyrus-page-jump-input"
29922
30076
  }
29923
30077
  ),
@@ -29972,6 +30126,7 @@ var styles10 = StyleSheet10.create({
29972
30126
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
29973
30127
  var Topbar = ({
29974
30128
  engine,
30129
+ documentType,
29975
30130
  onOpenSettings,
29976
30131
  onOpenOverflow,
29977
30132
  title,
@@ -29992,6 +30147,12 @@ var Topbar = ({
29992
30147
  locale
29993
30148
  } = useViewerStore9();
29994
30149
  const inkSession = useNativeInkSession();
30150
+ const chromeVisible = mobileChromeVisible || inkSession.active;
30151
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
30152
+ const chromeMotion = useAnimatedStyle(() => {
30153
+ "worklet";
30154
+ return { opacity: chromeProgress.value };
30155
+ });
29995
30156
  const t = getStrings(locale);
29996
30157
  const progress = useNativeInkMotion(inkSession.active, inkSession.supported);
29997
30158
  const settingsMotion = useAnimatedStyle(() => {
@@ -30047,26 +30208,30 @@ var Topbar = ({
30047
30208
  children: /* @__PURE__ */ jsx15(IconSettings, { size: MOBILE_CHROME_METRICS.iconSize, color: isDark ? "#e5e7eb" : "#111827" })
30048
30209
  }
30049
30210
  );
30050
- if (!mobileChromeVisible && !inkSession.active) return null;
30211
+ if (!chromeVisible && documentType !== "epub") return null;
30051
30212
  return /* @__PURE__ */ jsxs10(Fragment2, { children: [
30052
30213
  /* @__PURE__ */ jsx15(
30053
- View11,
30214
+ Animated3.View,
30054
30215
  {
30055
30216
  style: [
30056
30217
  styles11.chromeFrame,
30218
+ chromeMotion,
30057
30219
  {
30058
30220
  paddingTop: insets.top,
30059
30221
  paddingLeft: MOBILE_CHROME_METRICS.screenPadding + insets.left,
30060
30222
  paddingRight: MOBILE_CHROME_METRICS.screenPadding + insets.right
30061
30223
  }
30062
30224
  ],
30063
- pointerEvents: "box-none",
30225
+ pointerEvents: chromeVisible ? "box-none" : "none",
30226
+ accessibilityElementsHidden: !chromeVisible,
30227
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
30064
30228
  testID: "papyrus-floating-top-controls",
30065
30229
  children: /* @__PURE__ */ jsxs10(
30066
30230
  View11,
30067
30231
  {
30068
30232
  style: [
30069
30233
  styles11.container,
30234
+ Platform6.OS === "ios" && styles11.containerIos,
30070
30235
  isDark && styles11.containerDark,
30071
30236
  isLandscape && styles11.containerLandscape
30072
30237
  ],
@@ -30206,6 +30371,7 @@ var Topbar = ({
30206
30371
  /* @__PURE__ */ jsx15(
30207
30372
  PageJumpModal,
30208
30373
  {
30374
+ documentType,
30209
30375
  visible: jumpModalOpen,
30210
30376
  currentPage,
30211
30377
  pageCount,
@@ -30223,7 +30389,8 @@ var styles11 = StyleSheet11.create({
30223
30389
  maxWidth: MOBILE_CHROME_METRICS.maxFloatingWidth,
30224
30390
  marginTop: 10,
30225
30391
  paddingHorizontal: 14,
30226
- paddingVertical: 10,
30392
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30393
+ paddingVertical: 0,
30227
30394
  backgroundColor: "rgba(255,255,255,0.88)",
30228
30395
  borderWidth: 1,
30229
30396
  borderColor: "rgba(255,255,255,0.72)",
@@ -30240,6 +30407,10 @@ var styles11 = StyleSheet11.create({
30240
30407
  backgroundColor: "rgba(15,17,21,0.88)",
30241
30408
  borderColor: "rgba(71,85,105,0.48)"
30242
30409
  },
30410
+ containerIos: {
30411
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30412
+ paddingVertical: 0
30413
+ },
30243
30414
  containerLandscape: {
30244
30415
  maxWidth: void 0,
30245
30416
  marginTop: 0
@@ -31389,7 +31560,7 @@ import {
31389
31560
  } from "react";
31390
31561
  import {
31391
31562
  Image as Image2,
31392
- Platform as Platform6,
31563
+ Platform as Platform7,
31393
31564
  Pressable as Pressable8,
31394
31565
  StyleSheet as StyleSheet13,
31395
31566
  Text as Text7,
@@ -31470,7 +31641,7 @@ var PageThumbnail = ({
31470
31641
  if (!layoutReady || !useNativePreview || !shouldRenderPreview) return;
31471
31642
  const viewTag = findNodeHandle2(viewRef.current);
31472
31643
  if (!viewTag) return;
31473
- const isNative = Platform6.OS === "android" || Platform6.OS === "ios";
31644
+ const isNative = Platform7.OS === "android" || Platform7.OS === "ios";
31474
31645
  const renderScale = isNative ? 2 / Math.max(zoom, 0.5) : 2;
31475
31646
  void engine.renderPage(pageIndex, viewTag, renderScale);
31476
31647
  }, [
@@ -32395,14 +32566,14 @@ var RightSheet_default = RightSheet;
32395
32566
 
32396
32567
  // components/AnnotationEditor.tsx
32397
32568
  import { useEffect as useEffect13, useRef as useRef9, useState as useState12 } from "react";
32398
- import { AccessibilityInfo as AccessibilityInfo2, Alert as Alert3, Animated as Animated4, KeyboardAvoidingView, Modal as Modal3, Platform as Platform7, Pressable as Pressable9, ScrollView as ScrollView4, StyleSheet as StyleSheet14, Text as Text8, TextInput as TextInput2, View as View14 } from "react-native";
32569
+ import { AccessibilityInfo as AccessibilityInfo2, Alert as Alert3, Animated as Animated4, KeyboardAvoidingView, Modal as Modal3, Platform as Platform8, Pressable as Pressable9, ScrollView as ScrollView4, StyleSheet as StyleSheet14, Text as Text8, TextInput as TextInput2, View as View14 } from "react-native";
32399
32570
  import { getAnnotationEditPatch, getAnnotationMarkup as getAnnotationMarkup2, getAnnotationNote as getAnnotationNote2, getAnnotationQuote as getAnnotationQuote2, useViewerStore as useViewerStore12 } from "@papyrus-sdk/core";
32400
32571
  import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
32401
32572
  var COLORS = ["#fbbf24", "#fb7185", "#60a5fa", "#34d399", "#c084fc"];
32402
- var AnnotationEditor = () => {
32573
+ var AnnotationEditor = ({ documentId }) => {
32403
32574
  const { annotations, annotationDraft, clearAnnotationDraft, addAnnotation, selectedAnnotationId, updateAnnotation, removeAnnotation, setSelectedAnnotation, uiTheme, locale, accentColor } = useViewerStore12();
32404
32575
  const annotation = annotationDraft?.id === selectedAnnotationId ? annotationDraft : annotations.find((a) => a.id === selectedAnnotationId);
32405
- const supported = annotation && annotation.type !== "ink";
32576
+ const supported = annotation && annotation.type !== "ink" && (!documentId || !annotation.anchor?.documentId || annotation.anchor.documentId === documentId);
32406
32577
  const [editing, setEditing] = useState12(false);
32407
32578
  const [draft, setDraft] = useState12("");
32408
32579
  const [color, setColor] = useState12(COLORS[0]);
@@ -32462,19 +32633,39 @@ var AnnotationEditor = () => {
32462
32633
  const remove = () => Alert3.alert(t.deleteAnnotation, t.deleteAnnotationConfirmation, [{ text: t.cancel, style: "cancel" }, { text: t.deleteAnnotation, style: "destructive", onPress: () => deleteAnnotationAndClearSelection(annotation.id, removeAnnotation, setSelectedAnnotation) }]);
32463
32634
  const textStyle = { color: dark ? "#f9fafb" : "#111827" };
32464
32635
  const quote = getAnnotationQuote2(annotation);
32465
- return /* @__PURE__ */ jsx18(Modal3, { visible: true, transparent: true, animationType: "none", onRequestClose: close, children: /* @__PURE__ */ jsxs13(KeyboardAvoidingView, { behavior: Platform7.OS === "ios" ? "padding" : void 0, style: styles14.host, children: [
32636
+ return /* @__PURE__ */ jsx18(Modal3, { visible: true, transparent: true, animationType: "none", onRequestClose: close, children: /* @__PURE__ */ jsxs13(KeyboardAvoidingView, { behavior: Platform8.OS === "ios" ? "padding" : void 0, style: styles14.host, children: [
32466
32637
  /* @__PURE__ */ jsx18(Pressable9, { style: StyleSheet14.absoluteFill, onPress: close, accessibilityLabel: t.close }),
32467
32638
  /* @__PURE__ */ jsxs13(Animated4.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: [
32468
32639
  /* @__PURE__ */ jsxs13(View14, { style: styles14.header, children: [
32469
32640
  /* @__PURE__ */ jsx18(Text8, { style: [styles14.title, textStyle], children: editing ? t.editNote : t.annotationNote }),
32470
- /* @__PURE__ */ jsx18(Pressable9, { onPress: close, accessibilityRole: "button", accessibilityLabel: t.close, style: styles14.button, children: /* @__PURE__ */ jsx18(Text8, { style: textStyle, children: "\xD7" }) })
32641
+ /* @__PURE__ */ jsx18(Pressable9, { onPress: close, accessibilityRole: "button", accessibilityLabel: t.close, style: [styles14.button, { borderRadius: 22, backgroundColor: dark ? "#242936" : "#f1f5f9" }], children: /* @__PURE__ */ jsx18(IconClose, { size: 20, color: textStyle.color }) })
32471
32642
  ] }),
32472
32643
  /* @__PURE__ */ jsxs13(ScrollView4, { style: styles14.content, keyboardShouldPersistTaps: "handled", children: [
32473
32644
  quote ? /* @__PURE__ */ jsx18(Text8, { style: [styles14.quote, textStyle], selectable: true, children: quote }) : null,
32474
32645
  editing ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
32475
32646
  /* @__PURE__ */ jsx18(TextInput2, { accessibilityLabel: t.editNote, value: draft, onChangeText: setDraft, multiline: true, autoFocus: true, placeholder: t.notePlaceholder, placeholderTextColor: dark ? "#9ca3af" : "#6b7280", style: [styles14.input, textStyle, { borderColor: dark ? "#374151" : "#d1d5db" }] }),
32476
32647
  /* @__PURE__ */ jsx18(View14, { style: styles14.options, children: COLORS.map((value) => /* @__PURE__ */ jsx18(Pressable9, { accessibilityRole: "button", accessibilityLabel: `${t.annotationColor} ${value}`, accessibilityState: { selected: color === value }, onPress: () => setColor(value), style: [styles14.color, { backgroundColor: value, borderColor: color === value ? accentColor : "transparent" }] }, value)) }),
32477
- /* @__PURE__ */ jsx18(View14, { style: styles14.options, children: [["highlight", t.annotationHighlight], ["underline", t.annotationUnderline], ["strikeout", t.annotationStrikeout], ["none", t.annotationIndicatorOnly]].map(([style, label]) => /* @__PURE__ */ jsx18(Pressable9, { onPress: () => setMarkup(style), accessibilityRole: "button", accessibilityState: { selected: markup === style }, style: [styles14.button, markup === style && { borderColor: accentColor, borderWidth: 1 }], children: /* @__PURE__ */ jsx18(Text8, { style: textStyle, children: label }) }, style)) })
32648
+ /* @__PURE__ */ jsx18(View14, { style: styles14.markupOptions, children: [
32649
+ ["highlight", t.annotationHighlight, IconHighlight],
32650
+ ["underline", t.annotationUnderline, IconUnderline],
32651
+ ["strikeout", t.annotationStrikeout, IconStrikeout],
32652
+ ["none", t.annotationIndicatorOnly, IconComment]
32653
+ ].map(([style, label, Icon]) => /* @__PURE__ */ jsxs13(
32654
+ Pressable9,
32655
+ {
32656
+ onPress: () => setMarkup(style),
32657
+ accessibilityRole: "button",
32658
+ accessibilityLabel: label,
32659
+ accessibilityState: { selected: markup === style },
32660
+ testID: `annotation-style-${style}`,
32661
+ style: [styles14.markupButton, { backgroundColor: dark ? "#242936" : "#f1f5f9", borderColor: markup === style ? accentColor : "transparent" }],
32662
+ children: [
32663
+ /* @__PURE__ */ jsx18(View14, { accessible: false, importantForAccessibility: "no-hide-descendants", children: /* @__PURE__ */ jsx18(Icon, { size: 22, color: markup === style ? accentColor : textStyle.color }) }),
32664
+ /* @__PURE__ */ jsx18(Text8, { style: [styles14.markupLabel, textStyle], children: style === "none" ? locale === "pt-BR" ? "Indicador" : "Indicator" : label })
32665
+ ]
32666
+ },
32667
+ style
32668
+ )) })
32478
32669
  ] }) : /* @__PURE__ */ jsx18(Text8, { style: [styles14.note, textStyle], selectable: true, children: getAnnotationNote2(annotation) || t.notePlaceholder })
32479
32670
  ] }),
32480
32671
  /* @__PURE__ */ jsxs13(View14, { style: styles14.actions, children: [
@@ -32497,11 +32688,11 @@ var AnnotationEditor = () => {
32497
32688
  ] })
32498
32689
  ] }) });
32499
32690
  };
32500
- var styles14 = StyleSheet14.create({ host: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,.18)", paddingHorizontal: 12 }, card: { borderRadius: 20, padding: 16, maxHeight: "72%", elevation: 12 }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, title: { fontSize: 17, fontWeight: "700" }, content: { flexGrow: 0 }, quote: { fontSize: 14, lineHeight: 21, borderLeftWidth: 3, borderLeftColor: "#9ca3af", paddingLeft: 10, marginVertical: 12 }, note: { fontSize: 16, lineHeight: 24, paddingVertical: 12 }, input: { minHeight: 112, maxHeight: 240, borderWidth: 1, borderRadius: 12, padding: 12, fontSize: 16, textAlignVertical: "top" }, button: { minWidth: 44, minHeight: 44, paddingHorizontal: 10, borderRadius: 10, alignItems: "center", justifyContent: "center" }, actions: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", marginTop: 12 }, options: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, color: { width: 44, height: 44, borderRadius: 22, borderWidth: 3 } });
32691
+ var styles14 = StyleSheet14.create({ host: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,.18)", paddingHorizontal: 12 }, card: { borderRadius: 20, padding: 16, maxHeight: "72%", elevation: 12 }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, title: { fontSize: 17, fontWeight: "700" }, content: { flexGrow: 0 }, quote: { fontSize: 14, lineHeight: 21, borderLeftWidth: 3, borderLeftColor: "#9ca3af", paddingLeft: 10, marginVertical: 12 }, note: { fontSize: 16, lineHeight: 24, paddingVertical: 12 }, input: { minHeight: 112, maxHeight: 240, borderWidth: 1, borderRadius: 12, padding: 12, fontSize: 16, textAlignVertical: "top" }, button: { minWidth: 44, minHeight: 44, paddingHorizontal: 10, borderRadius: 10, alignItems: "center", justifyContent: "center" }, actions: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", marginTop: 12 }, markupOptions: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, markupButton: { flex: 1, minWidth: 64, minHeight: 64, borderWidth: 1, borderRadius: 12, paddingHorizontal: 4, paddingVertical: 8, alignItems: "center", justifyContent: "center", gap: 6 }, markupLabel: { fontSize: 11, lineHeight: 15, textAlign: "center" }, options: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, color: { width: 44, height: 44, borderRadius: 22, borderWidth: 3 } });
32501
32692
  var AnnotationEditor_default = AnnotationEditor;
32502
32693
 
32503
32694
  // components/BottomBar.tsx
32504
- import { View as View15, Pressable as Pressable10, StyleSheet as StyleSheet15, useWindowDimensions as useWindowDimensions7 } from "react-native";
32695
+ import { View as View15, Text as Text9, Pressable as Pressable10, StyleSheet as StyleSheet15, useWindowDimensions as useWindowDimensions7 } from "react-native";
32505
32696
  import { useViewerStore as useViewerStore13 } from "@papyrus-sdk/core";
32506
32697
  import Animated5, { useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
32507
32698
 
@@ -32555,15 +32746,24 @@ function resolveAnnotateButtonAction(input) {
32555
32746
  }
32556
32747
 
32557
32748
  // components/BottomBar.tsx
32558
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
32749
+ import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
32559
32750
  var BottomBar = ({
32560
32751
  documentType,
32561
32752
  onOpenInfo,
32562
32753
  onOpenSettings,
32563
- onOpenDestination
32754
+ onOpenDestination,
32755
+ onTurnPage,
32756
+ onNavigateToPage,
32757
+ onOpenPages
32564
32758
  }) => {
32565
32759
  const {
32566
32760
  activeMobileDestination,
32761
+ viewMode,
32762
+ epubReadingMode,
32763
+ epubLocation,
32764
+ comicLayoutMode,
32765
+ currentPage,
32766
+ pageCount,
32567
32767
  mobileDockVisible,
32568
32768
  setDocumentState,
32569
32769
  uiTheme,
@@ -32578,7 +32778,7 @@ var BottomBar = ({
32578
32778
  const supportsInkChrome = documentType === "pdf" && inkSession.supported;
32579
32779
  const drawing = supportsInkChrome && inkSession.active;
32580
32780
  const dockVisible = mobileChromeVisible && mobileDockVisible && !drawing;
32581
- const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome);
32781
+ const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome || documentType === "epub");
32582
32782
  const dockMotion = useAnimatedStyle2(() => {
32583
32783
  "worklet";
32584
32784
  return {
@@ -32600,6 +32800,15 @@ var BottomBar = ({
32600
32800
  activeMobileDestination,
32601
32801
  toolDockOpen
32602
32802
  });
32803
+ const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single");
32804
+ if (paginated) {
32805
+ layout.leftSlots.push(...layout.rightSlots.filter((slot) => slot.key === "search"));
32806
+ layout.rightSlots = [];
32807
+ }
32808
+ const turnPage = (direction) => {
32809
+ if (onTurnPage) onTurnPage(direction);
32810
+ else onNavigateToPage?.(currentPage + direction);
32811
+ };
32603
32812
  const slotMeta = {
32604
32813
  annotate: {
32605
32814
  label: t.tools,
@@ -32660,7 +32869,7 @@ var BottomBar = ({
32660
32869
  onPress: onOpenSettings
32661
32870
  }
32662
32871
  };
32663
- if (!dockVisible && !supportsInkChrome) return null;
32872
+ if (!dockVisible && !supportsInkChrome && documentType !== "epub") return null;
32664
32873
  return /* @__PURE__ */ jsx19(
32665
32874
  Animated5.View,
32666
32875
  {
@@ -32725,7 +32934,11 @@ var BottomBar = ({
32725
32934
  isDark && styles15.islandDark
32726
32935
  ],
32727
32936
  testID: "papyrus-floating-bottom-dock",
32728
- children: layout.rightSlots.map((slot) => {
32937
+ children: paginated ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
32938
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "P\xE1gina anterior" : "Previous page", disabled: !dockVisible || (documentType === "epub" ? epubLocation?.atStart : !onTurnPage && currentPage <= 1), onPress: () => turnPage(-1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
32939
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Ir para p\xE1gina" : "Go to page", onPress: onOpenPages, style: [styles15.iconOnlyItem, { minWidth: 56 }], children: /* @__PURE__ */ jsx19(Text9, { style: { color: iconColor(false), fontWeight: "700", fontSize: 13, lineHeight: 18, includeFontPadding: false }, children: documentType === "epub" ? epubLocation?.visualPage ? `Cap. ${epubLocation.chapter} \xB7 ${epubLocation.visualPage}/${epubLocation.visualPageCount}` : `Cap. ${currentPage}` : `${currentPage}/${pageCount}` }) }),
32940
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Pr\xF3xima p\xE1gina" : "Next page", disabled: !dockVisible || (documentType === "epub" ? epubLocation?.atEnd : !onTurnPage && currentPage >= pageCount), onPress: () => turnPage(1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
32941
+ ] }) : layout.rightSlots.map((slot) => {
32729
32942
  const meta = slotMeta[slot.key];
32730
32943
  const Icon = meta.icon;
32731
32944
  return /* @__PURE__ */ jsx19(
@@ -32788,8 +33001,9 @@ var styles15 = StyleSheet15.create({
32788
33001
  island: {
32789
33002
  flexDirection: "row",
32790
33003
  alignItems: "center",
32791
- paddingVertical: 8,
32792
- paddingHorizontal: 10,
33004
+ height: MOBILE_CHROME_METRICS.bottomBarVisualHeight,
33005
+ paddingVertical: 0,
33006
+ paddingHorizontal: 6,
32793
33007
  backgroundColor: "rgba(255,255,255,0.9)",
32794
33008
  borderWidth: 1,
32795
33009
  borderColor: "rgba(255,255,255,0.72)",
@@ -32815,6 +33029,8 @@ var styles15 = StyleSheet15.create({
32815
33029
  borderColor: "rgba(71,85,105,0.48)"
32816
33030
  },
32817
33031
  iconOnlyItem: {
33032
+ minWidth: 44,
33033
+ height: 44,
32818
33034
  alignItems: "center",
32819
33035
  justifyContent: "center",
32820
33036
  paddingHorizontal: MOBILE_CHROME_METRICS.bottomBarItemPaddingHorizontal,
@@ -32845,9 +33061,9 @@ var BottomBar_default = BottomBar;
32845
33061
  // components/SettingsSheet.tsx
32846
33062
  import {
32847
33063
  View as View16,
32848
- Text as Text9,
33064
+ Text as Text10,
32849
33065
  Pressable as Pressable11,
32850
- Platform as Platform8,
33066
+ Platform as Platform9,
32851
33067
  StyleSheet as StyleSheet16,
32852
33068
  useWindowDimensions as useWindowDimensions8
32853
33069
  } from "react-native";
@@ -32898,10 +33114,12 @@ var SettingsSheet = ({
32898
33114
  engine,
32899
33115
  visible,
32900
33116
  onClose,
32901
- documentType = "pdf"
33117
+ documentType = "pdf",
33118
+ onOpenInfo
32902
33119
  }) => {
32903
33120
  const {
32904
33121
  viewMode,
33122
+ epubReadingMode,
32905
33123
  uiTheme,
32906
33124
  zoom,
32907
33125
  setDocumentState,
@@ -32913,12 +33131,16 @@ var SettingsSheet = ({
32913
33131
  comicReadingDirection
32914
33132
  } = useViewerStore14();
32915
33133
  const isDark = uiTheme === "dark";
32916
- const isPaged = viewMode === "single";
33134
+ const isPaged = documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single";
32917
33135
  const isDouble = viewMode === "double";
32918
33136
  const t = getStrings(locale);
32919
33137
  const { height: windowHeight } = useWindowDimensions8();
32920
33138
  const sheetMaxHeight = getSettingsSheetMaxHeight(windowHeight);
32921
33139
  const handleTransition = (mode) => {
33140
+ if (documentType === "epub") {
33141
+ setDocumentState({ epubReadingMode: mode === "paged" ? "paged" : "chapter-scroll" });
33142
+ return;
33143
+ }
32922
33144
  if (mode === "paged") {
32923
33145
  setDocumentState({ viewMode: "single" });
32924
33146
  return;
@@ -32963,22 +33185,23 @@ var SettingsSheet = ({
32963
33185
  contentContainerStyle: styles16.sheetContent,
32964
33186
  showsVerticalScrollIndicator: false,
32965
33187
  children: [
33188
+ onOpenInfo ? /* @__PURE__ */ jsx20(Pressable11, { accessibilityRole: "button", onPress: onOpenInfo, style: { minHeight: 44, justifyContent: "center", marginBottom: 16 }, children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.info }) }) : null,
32966
33189
  (documentType === "text" || documentType === "epub") && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
32967
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: locale === "pt-BR" ? "Tamanho da fonte" : "Font size" }),
33190
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: locale === "pt-BR" ? "Tamanho da fonte" : "Font size" }),
32968
33191
  /* @__PURE__ */ jsxs15(View16, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
32969
33192
  [-0.1, 0.1].map((delta) => /* @__PURE__ */ jsx20(Pressable11, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? delta < 0 ? "Diminuir fonte" : "Aumentar fonte" : delta < 0 ? "Decrease font" : "Increase font", onPress: () => {
32970
33193
  const next = Math.max(0.7, Math.min(2, zoom + delta));
32971
33194
  if (documentType === "epub") engine.setZoom(next);
32972
33195
  setDocumentState({ zoom: next });
32973
- }, style: { minWidth: 44, minHeight: 44, justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx20(Text9, { style: { fontSize: 20, color: isDark ? "#fff" : "#111" }, children: delta < 0 ? "A\u2212" : "A+" }) }, delta)),
32974
- /* @__PURE__ */ jsxs15(Text9, { style: { color: isDark ? "#fff" : "#111" }, children: [
33196
+ }, style: { minWidth: 44, minHeight: 44, justifyContent: "center", alignItems: "center" }, children: /* @__PURE__ */ jsx20(Text10, { style: { fontSize: 20, color: isDark ? "#fff" : "#111" }, children: delta < 0 ? "A\u2212" : "A+" }) }, delta)),
33197
+ /* @__PURE__ */ jsxs15(Text10, { style: { color: isDark ? "#fff" : "#111" }, children: [
32975
33198
  Math.round(zoom * 100),
32976
33199
  "%"
32977
33200
  ] })
32978
33201
  ] })
32979
33202
  ] }),
32980
33203
  documentType === "comic" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
32981
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicMode }),
33204
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicMode }),
32982
33205
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["single", "continuous"].map((mode) => {
32983
33206
  const active = comicLayoutMode === mode;
32984
33207
  return /* @__PURE__ */ jsx20(
@@ -32986,12 +33209,12 @@ var SettingsSheet = ({
32986
33209
  {
32987
33210
  onPress: () => setDocumentState({ comicLayoutMode: mode }),
32988
33211
  style: [styles16.optionButton, isDark && styles16.optionButtonDark, active && styles16.optionButtonActive, active && { backgroundColor: accentColor }],
32989
- children: /* @__PURE__ */ jsx20(Text9, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "single" ? t.comicSingle : t.comicContinuous })
33212
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "single" ? t.comicSingle : t.comicContinuous })
32990
33213
  },
32991
33214
  mode
32992
33215
  );
32993
33216
  }) }),
32994
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicFit }),
33217
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicFit }),
32995
33218
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["width", "page"].map((mode) => {
32996
33219
  const active = comicFitMode === mode;
32997
33220
  return /* @__PURE__ */ jsx20(
@@ -32999,12 +33222,12 @@ var SettingsSheet = ({
32999
33222
  {
33000
33223
  onPress: () => setDocumentState({ comicFitMode: mode }),
33001
33224
  style: [styles16.optionButton, isDark && styles16.optionButtonDark, active && styles16.optionButtonActive, active && { backgroundColor: accentColor }],
33002
- children: /* @__PURE__ */ jsx20(Text9, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "width" ? t.comicFitWidth : t.comicFitPage })
33225
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "width" ? t.comicFitWidth : t.comicFitPage })
33003
33226
  },
33004
33227
  mode
33005
33228
  );
33006
33229
  }) }),
33007
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicDirection }),
33230
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicDirection }),
33008
33231
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["ltr", "rtl"].map((direction) => {
33009
33232
  const active = comicReadingDirection === direction;
33010
33233
  return /* @__PURE__ */ jsx20(
@@ -33012,7 +33235,7 @@ var SettingsSheet = ({
33012
33235
  {
33013
33236
  onPress: () => setDocumentState({ comicReadingDirection: direction }),
33014
33237
  style: [styles16.optionButton, isDark && styles16.optionButtonDark, active && styles16.optionButtonActive, active && { backgroundColor: accentColor }],
33015
- children: /* @__PURE__ */ jsx20(Text9, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: direction === "ltr" ? t.comicLtr : t.comicRtl })
33238
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: direction === "ltr" ? t.comicLtr : t.comicRtl })
33016
33239
  },
33017
33240
  direction
33018
33241
  );
@@ -33020,7 +33243,7 @@ var SettingsSheet = ({
33020
33243
  ] }),
33021
33244
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33022
33245
  /* @__PURE__ */ jsx20(
33023
- Text9,
33246
+ Text10,
33024
33247
  {
33025
33248
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33026
33249
  children: t.appearance
@@ -33038,7 +33261,7 @@ var SettingsSheet = ({
33038
33261
  uiTheme === "light" && { backgroundColor: accentColor }
33039
33262
  ],
33040
33263
  children: /* @__PURE__ */ jsx20(
33041
- Text9,
33264
+ Text10,
33042
33265
  {
33043
33266
  style: [
33044
33267
  styles16.optionText,
@@ -33061,7 +33284,7 @@ var SettingsSheet = ({
33061
33284
  uiTheme === "dark" && { backgroundColor: accentColor }
33062
33285
  ],
33063
33286
  children: /* @__PURE__ */ jsx20(
33064
- Text9,
33287
+ Text10,
33065
33288
  {
33066
33289
  style: [
33067
33290
  styles16.optionText,
@@ -33077,7 +33300,7 @@ var SettingsSheet = ({
33077
33300
  ] }),
33078
33301
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33079
33302
  /* @__PURE__ */ jsx20(
33080
- Text9,
33303
+ Text10,
33081
33304
  {
33082
33305
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33083
33306
  children: t.pageTheme
@@ -33098,7 +33321,7 @@ var SettingsSheet = ({
33098
33321
  children: [
33099
33322
  /* @__PURE__ */ jsx20(ThemeSwatch, { value: option.value }),
33100
33323
  /* @__PURE__ */ jsx20(
33101
- Text9,
33324
+ Text10,
33102
33325
  {
33103
33326
  style: [
33104
33327
  styles16.themeOptionLabel,
@@ -33116,7 +33339,7 @@ var SettingsSheet = ({
33116
33339
  ] }),
33117
33340
  documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33118
33341
  /* @__PURE__ */ jsx20(
33119
- Text9,
33342
+ Text10,
33120
33343
  {
33121
33344
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33122
33345
  children: t.pageTransition
@@ -33134,14 +33357,14 @@ var SettingsSheet = ({
33134
33357
  (!isPaged || isDouble) && { backgroundColor: accentColor }
33135
33358
  ],
33136
33359
  children: /* @__PURE__ */ jsx20(
33137
- Text9,
33360
+ Text10,
33138
33361
  {
33139
33362
  style: [
33140
33363
  styles16.optionText,
33141
33364
  isDark && styles16.optionTextDark,
33142
33365
  (!isPaged || isDouble) && styles16.optionTextActive
33143
33366
  ],
33144
- children: t.continuous
33367
+ children: documentType === "epub" && locale === "pt-BR" ? "Rolagem por cap\xEDtulo" : t.continuous
33145
33368
  }
33146
33369
  )
33147
33370
  }
@@ -33157,7 +33380,7 @@ var SettingsSheet = ({
33157
33380
  isPaged && { backgroundColor: accentColor }
33158
33381
  ],
33159
33382
  children: /* @__PURE__ */ jsx20(
33160
- Text9,
33383
+ Text10,
33161
33384
  {
33162
33385
  style: [
33163
33386
  styles16.optionText,
@@ -33171,9 +33394,9 @@ var SettingsSheet = ({
33171
33394
  )
33172
33395
  ] })
33173
33396
  ] }),
33174
- documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33397
+ documentType === "pdf" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33175
33398
  /* @__PURE__ */ jsx20(
33176
- Text9,
33399
+ Text10,
33177
33400
  {
33178
33401
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33179
33402
  children: t.layout
@@ -33191,7 +33414,7 @@ var SettingsSheet = ({
33191
33414
  !isDouble && { backgroundColor: accentColor }
33192
33415
  ],
33193
33416
  children: /* @__PURE__ */ jsx20(
33194
- Text9,
33417
+ Text10,
33195
33418
  {
33196
33419
  style: [
33197
33420
  styles16.optionText,
@@ -33214,7 +33437,7 @@ var SettingsSheet = ({
33214
33437
  isDouble && { backgroundColor: accentColor }
33215
33438
  ],
33216
33439
  children: /* @__PURE__ */ jsx20(
33217
- Text9,
33440
+ Text10,
33218
33441
  {
33219
33442
  style: [
33220
33443
  styles16.optionText,
@@ -33230,7 +33453,7 @@ var SettingsSheet = ({
33230
33453
  ] }),
33231
33454
  documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33232
33455
  /* @__PURE__ */ jsx20(
33233
- Text9,
33456
+ Text10,
33234
33457
  {
33235
33458
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33236
33459
  children: t.rotate
@@ -33243,7 +33466,7 @@ var SettingsSheet = ({
33243
33466
  onPress: () => handleRotate("counterclockwise"),
33244
33467
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33245
33468
  children: /* @__PURE__ */ jsx20(
33246
- Text9,
33469
+ Text10,
33247
33470
  {
33248
33471
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33249
33472
  children: t.counterclockwise
@@ -33251,13 +33474,13 @@ var SettingsSheet = ({
33251
33474
  )
33252
33475
  }
33253
33476
  ),
33254
- Platform8.OS === "ios" && /* @__PURE__ */ jsx20(
33477
+ Platform9.OS === "ios" && /* @__PURE__ */ jsx20(
33255
33478
  Pressable11,
33256
33479
  {
33257
33480
  onPress: handleResetRotation,
33258
33481
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33259
33482
  children: /* @__PURE__ */ jsx20(
33260
- Text9,
33483
+ Text10,
33261
33484
  {
33262
33485
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33263
33486
  children: t.rotationOriginal
@@ -33271,7 +33494,7 @@ var SettingsSheet = ({
33271
33494
  onPress: () => handleRotate("clockwise"),
33272
33495
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33273
33496
  children: /* @__PURE__ */ jsx20(
33274
- Text9,
33497
+ Text10,
33275
33498
  {
33276
33499
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33277
33500
  children: t.clockwise
@@ -33283,7 +33506,7 @@ var SettingsSheet = ({
33283
33506
  ] }),
33284
33507
  documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33285
33508
  /* @__PURE__ */ jsx20(
33286
- Text9,
33509
+ Text10,
33287
33510
  {
33288
33511
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33289
33512
  children: t.zoom
@@ -33298,7 +33521,7 @@ var SettingsSheet = ({
33298
33521
  children: /* @__PURE__ */ jsx20(IconZoomOut, { size: 16, color: isDark ? "#e5e7eb" : "#111827" })
33299
33522
  }
33300
33523
  ),
33301
- /* @__PURE__ */ jsx20(View16, { style: styles16.zoomValue, children: /* @__PURE__ */ jsxs15(Text9, { style: [styles16.zoomText, isDark && styles16.zoomTextDark], children: [
33524
+ /* @__PURE__ */ jsx20(View16, { style: styles16.zoomValue, children: /* @__PURE__ */ jsxs15(Text10, { style: [styles16.zoomText, isDark && styles16.zoomTextDark], children: [
33302
33525
  Math.round(zoom * 100),
33303
33526
  "%"
33304
33527
  ] }) }),
@@ -33314,7 +33537,7 @@ var SettingsSheet = ({
33314
33537
  ] }),
33315
33538
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33316
33539
  /* @__PURE__ */ jsx20(
33317
- Text9,
33540
+ Text10,
33318
33541
  {
33319
33542
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33320
33543
  children: t.language
@@ -33332,7 +33555,7 @@ var SettingsSheet = ({
33332
33555
  locale === "en" && { backgroundColor: accentColor }
33333
33556
  ],
33334
33557
  children: /* @__PURE__ */ jsx20(
33335
- Text9,
33558
+ Text10,
33336
33559
  {
33337
33560
  style: [
33338
33561
  styles16.optionText,
@@ -33355,7 +33578,7 @@ var SettingsSheet = ({
33355
33578
  locale === "pt-BR" && { backgroundColor: accentColor }
33356
33579
  ],
33357
33580
  children: /* @__PURE__ */ jsx20(
33358
- Text9,
33581
+ Text10,
33359
33582
  {
33360
33583
  style: [
33361
33584
  styles16.optionText,
@@ -33512,7 +33735,7 @@ import { useEffect as useEffect14, useMemo as useMemo8, useRef as useRef10, useS
33512
33735
  import {
33513
33736
  ActivityIndicator,
33514
33737
  StyleSheet as StyleSheet17,
33515
- Text as Text10,
33738
+ Text as Text11,
33516
33739
  UIManager as UIManager2,
33517
33740
  View as View17,
33518
33741
  findNodeHandle as findNodeHandle3
@@ -33635,12 +33858,12 @@ var CoverPreview = ({
33635
33858
  }
33636
33859
  };
33637
33860
  if (!shouldRender || !canRender) {
33638
- return /* @__PURE__ */ jsx21(View17, { style: [styles17.container, style], children: placeholder ?? /* @__PURE__ */ jsx21(View17, { style: styles17.placeholder, children: /* @__PURE__ */ jsx21(Text10, { style: styles17.placeholderText, children: "Preview" }) }) });
33861
+ return /* @__PURE__ */ jsx21(View17, { style: [styles17.container, style], children: placeholder ?? /* @__PURE__ */ jsx21(View17, { style: styles17.placeholder, children: /* @__PURE__ */ jsx21(Text11, { style: styles17.placeholderText, children: "Preview" }) }) });
33639
33862
  }
33640
33863
  return /* @__PURE__ */ jsxs16(View17, { style: [styles17.container, style], onLayout: handleLayout, children: [
33641
33864
  /* @__PURE__ */ jsx21(View17, { style: styles17.previewFrame, pointerEvents: allowInteraction ? "auto" : "none", children: isPdf ? /* @__PURE__ */ jsx21(PapyrusPageView3, { ref: viewRef, style: styles17.pageView }) : engine && /* @__PURE__ */ jsx21(WebViewViewer_default, { engine }) }),
33642
33865
  showLoading && loading && /* @__PURE__ */ jsx21(View17, { pointerEvents: "none", style: styles17.loadingOverlay, children: loadingIndicator ?? /* @__PURE__ */ jsx21(ActivityIndicator, { size: "small", color: "#2563eb" }) }),
33643
- error && /* @__PURE__ */ jsx21(View17, { pointerEvents: "none", style: styles17.errorOverlay, children: /* @__PURE__ */ jsx21(Text10, { style: styles17.errorText, children: "Preview unavailable" }) })
33866
+ error && /* @__PURE__ */ jsx21(View17, { pointerEvents: "none", style: styles17.errorOverlay, children: /* @__PURE__ */ jsx21(Text11, { style: styles17.errorText, children: "Preview unavailable" }) })
33644
33867
  ] });
33645
33868
  };
33646
33869
  var styles17 = StyleSheet17.create({
@@ -33695,7 +33918,7 @@ import { Keyboard as Keyboard2, View as View23, StyleSheet as StyleSheet24 } fro
33695
33918
  import { useViewerStore as useViewerStore21 } from "@papyrus-sdk/core";
33696
33919
 
33697
33920
  // components/DocumentActionsSheet.tsx
33698
- import { StyleSheet as StyleSheet18, Text as Text11, View as View18 } from "react-native";
33921
+ import { StyleSheet as StyleSheet18, Text as Text12, View as View18 } from "react-native";
33699
33922
  import { useViewerStore as useViewerStore15 } from "@papyrus-sdk/core";
33700
33923
  import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
33701
33924
  function DocumentActionsSheet({
@@ -33732,7 +33955,7 @@ function DocumentActionsSheet({
33732
33955
  borderColor: palette.divider
33733
33956
  }
33734
33957
  ],
33735
- children: /* @__PURE__ */ jsx22(Text11, { style: [styles18.actionText, { color: palette.text }], children: "Share" })
33958
+ children: /* @__PURE__ */ jsx22(Text12, { style: [styles18.actionText, { color: palette.text }], children: "Share" })
33736
33959
  }
33737
33960
  ),
33738
33961
  /* @__PURE__ */ jsx22(
@@ -33745,7 +33968,7 @@ function DocumentActionsSheet({
33745
33968
  borderColor: palette.divider
33746
33969
  }
33747
33970
  ],
33748
- children: /* @__PURE__ */ jsx22(Text11, { style: [styles18.actionText, { color: palette.text }], children: "Export" })
33971
+ children: /* @__PURE__ */ jsx22(Text12, { style: [styles18.actionText, { color: palette.text }], children: "Export" })
33749
33972
  }
33750
33973
  )
33751
33974
  ] })
@@ -33770,7 +33993,7 @@ var styles18 = StyleSheet18.create({
33770
33993
  });
33771
33994
 
33772
33995
  // components/InfoSheet.tsx
33773
- import { StyleSheet as StyleSheet19, Text as Text12, View as View19 } from "react-native";
33996
+ import { StyleSheet as StyleSheet19, Text as Text13, View as View19 } from "react-native";
33774
33997
  import { useViewerStore as useViewerStore16 } from "@papyrus-sdk/core";
33775
33998
 
33776
33999
  // components/infoSheetModel.ts
@@ -33924,15 +34147,15 @@ function InfoSheet({
33924
34147
  contentContainerStyle: styles19.contentInner,
33925
34148
  showsVerticalScrollIndicator: false,
33926
34149
  children: [
33927
- /* @__PURE__ */ jsx23(Text12, { style: [styles19.sectionTitle, { color: palette.mutedText }], children: isPortuguese ? "Resumo do documento" : "Document summary" }),
34150
+ /* @__PURE__ */ jsx23(Text13, { style: [styles19.sectionTitle, { color: palette.mutedText }], children: isPortuguese ? "Resumo do documento" : "Document summary" }),
33928
34151
  /* @__PURE__ */ jsx23(View19, { style: [styles19.rows, { borderTopColor: palette.divider }], children: rows.map((row) => /* @__PURE__ */ jsxs18(
33929
34152
  View19,
33930
34153
  {
33931
34154
  style: [styles19.row, { borderBottomColor: palette.divider }],
33932
34155
  children: [
33933
- /* @__PURE__ */ jsx23(Text12, { style: [styles19.label, { color: palette.mutedText }], children: row.label }),
34156
+ /* @__PURE__ */ jsx23(Text13, { style: [styles19.label, { color: palette.mutedText }], children: row.label }),
33934
34157
  /* @__PURE__ */ jsx23(
33935
- Text12,
34158
+ Text13,
33936
34159
  {
33937
34160
  style: [styles19.value, { color: palette.text }],
33938
34161
  selectable: true,
@@ -33995,7 +34218,7 @@ var styles19 = StyleSheet19.create({
33995
34218
  });
33996
34219
 
33997
34220
  // components/OverflowSheet.tsx
33998
- import { Pressable as Pressable12, StyleSheet as StyleSheet20, Text as Text13, View as View20 } from "react-native";
34221
+ import { Pressable as Pressable12, StyleSheet as StyleSheet20, Text as Text14, View as View20 } from "react-native";
33999
34222
  import { useViewerStore as useViewerStore17 } from "@papyrus-sdk/core";
34000
34223
  import { jsx as jsx24 } from "react/jsx-runtime";
34001
34224
  var actionLabels = [{ key: "actions", label: "Document actions" }];
@@ -34035,7 +34258,7 @@ function OverflowSheet({
34035
34258
  ],
34036
34259
  accessibilityRole: "button",
34037
34260
  accessibilityLabel: action.label,
34038
- children: /* @__PURE__ */ jsx24(Text13, { style: [styles20.actionText, { color: palette.text }], children: action.label })
34261
+ children: /* @__PURE__ */ jsx24(Text14, { style: [styles20.actionText, { color: palette.text }], children: action.label })
34039
34262
  },
34040
34263
  action.key
34041
34264
  )) })
@@ -34060,10 +34283,11 @@ import {
34060
34283
  PanResponder as PanResponder2,
34061
34284
  Pressable as Pressable13,
34062
34285
  StyleSheet as StyleSheet21,
34063
- Text as Text14,
34286
+ Text as Text15,
34064
34287
  View as View21,
34065
34288
  useWindowDimensions as useWindowDimensions9
34066
34289
  } from "react-native";
34290
+ import Reanimated, { useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
34067
34291
  import { useViewerStore as useViewerStore18 } from "@papyrus-sdk/core";
34068
34292
 
34069
34293
  // components/progressPillMode.ts
@@ -34083,9 +34307,11 @@ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
34083
34307
  var clampPercent = (value) => Math.max(0, Math.min(100, Math.round(value)));
34084
34308
  function ProgressPill({
34085
34309
  documentType,
34310
+ navigationInDock = false,
34086
34311
  onPress,
34087
34312
  onOpenPageJump,
34088
34313
  onNavigateToPage,
34314
+ onTurnPage,
34089
34315
  onScrubbingChange
34090
34316
  }) {
34091
34317
  const {
@@ -34095,12 +34321,20 @@ function ProgressPill({
34095
34321
  textLength,
34096
34322
  comicLayoutMode,
34097
34323
  viewMode,
34324
+ epubReadingMode,
34325
+ epubLocation,
34098
34326
  locale,
34099
34327
  uiTheme,
34100
34328
  accentColor,
34101
34329
  mobileChromeVisible,
34102
34330
  mobileProgressPillVisible
34103
34331
  } = useViewerStore18();
34332
+ const chromeVisible = mobileChromeVisible && mobileProgressPillVisible;
34333
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
34334
+ const chromeMotion = useAnimatedStyle3(() => {
34335
+ "worklet";
34336
+ return { opacity: chromeProgress.value };
34337
+ });
34104
34338
  const t = getStrings(locale);
34105
34339
  const isDark = uiTheme === "dark";
34106
34340
  const offsets = resolveMobileChromeOffsets(usePapyrusSafeAreaInsets());
@@ -34145,10 +34379,10 @@ function ProgressPill({
34145
34379
  return `${displayedPage}/${pageCount || 0}`;
34146
34380
  }
34147
34381
  if (documentType === "epub") {
34148
- return `Cap. ${displayedPage} \xB7 ${percent}%`;
34382
+ return `Cap. ${displayedPage} \xB7 ${scrubPreviewPage === null && epubLocation ? clampPercent(epubLocation.progress * 100) : percent}%`;
34149
34383
  }
34150
34384
  return `${percent}%`;
34151
- }, [displayedPage, documentType, pageCount]);
34385
+ }, [displayedPage, documentType, pageCount, epubLocation, scrubPreviewPage]);
34152
34386
  const thumbTop = resolvePageScrubberThumbTop({
34153
34387
  currentPage,
34154
34388
  trackHeight,
@@ -34190,7 +34424,7 @@ function ProgressPill({
34190
34424
  },
34191
34425
  []
34192
34426
  );
34193
- if (!shouldRenderPageScrubber({
34427
+ if (!(documentType === "epub" && mobileProgressPillVisible) && !shouldRenderPageScrubber({
34194
34428
  mobileChromeVisible,
34195
34429
  mobileProgressPillVisible,
34196
34430
  isScrubbing: isScrubbingRef.current
@@ -34212,7 +34446,7 @@ function ProgressPill({
34212
34446
  onPress: () => onPressRef.current(),
34213
34447
  style: [styles21.singlePill, isDark && styles21.pillDark],
34214
34448
  testID: "papyrus-progress-text",
34215
- children: /* @__PURE__ */ jsxs19(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: [
34449
+ children: /* @__PURE__ */ jsxs19(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: [
34216
34450
  progress,
34217
34451
  "%"
34218
34452
  ] })
@@ -34221,16 +34455,17 @@ function ProgressPill({
34221
34455
  }
34222
34456
  );
34223
34457
  }
34224
- const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : viewMode;
34458
+ const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : documentType === "epub" ? epubReadingMode === "paged" ? "single" : "continuous" : viewMode;
34225
34459
  const pillMode = resolveProgressPillMode(progressViewMode, currentPage, pageCount);
34460
+ if (pillMode.kind === "navigation" && navigationInDock) return null;
34226
34461
  if (pillMode.kind === "navigation") {
34227
- const previousDisabled = pillMode.previousPage === null || !onNavigateToPage;
34228
- const nextDisabled = pillMode.nextPage === null || !onNavigateToPage;
34462
+ const previousDisabled = !onTurnPage && (pillMode.previousPage === null || !onNavigateToPage);
34463
+ const nextDisabled = !onTurnPage && (pillMode.nextPage === null || !onNavigateToPage);
34229
34464
  return /* @__PURE__ */ jsx25(
34230
34465
  View21,
34231
34466
  {
34232
34467
  pointerEvents: "box-none",
34233
- 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" }],
34234
34469
  children: /* @__PURE__ */ jsxs19(View21, { style: [styles21.singlePill, isDark && styles21.pillDark], children: [
34235
34470
  /* @__PURE__ */ jsx25(
34236
34471
  Pressable13,
@@ -34239,10 +34474,10 @@ function ProgressPill({
34239
34474
  accessibilityLabel: t.previousPage,
34240
34475
  accessibilityState: { disabled: previousDisabled },
34241
34476
  disabled: previousDisabled,
34242
- onPress: () => pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34477
+ onPress: () => onTurnPage ? onTurnPage(-1) : pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34243
34478
  style: styles21.pageArrowHit,
34244
34479
  testID: "papyrus-progress-page-previous",
34245
- children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.pageArrow, isDark && styles21.labelDark, previousDisabled && styles21.pageArrowDisabled], children: "\u2039" })
34480
+ children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.pageArrow, isDark && styles21.labelDark, previousDisabled && styles21.pageArrowDisabled], children: "\u2039" })
34246
34481
  }
34247
34482
  ),
34248
34483
  /* @__PURE__ */ jsx25(
@@ -34253,7 +34488,7 @@ function ProgressPill({
34253
34488
  onPress: () => onPressRef.current(),
34254
34489
  style: styles21.singlePageCenter,
34255
34490
  testID: "papyrus-progress-page-grid",
34256
- children: /* @__PURE__ */ jsxs19(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: [
34491
+ children: /* @__PURE__ */ jsxs19(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: [
34257
34492
  currentPage,
34258
34493
  "/",
34259
34494
  pageCount || 0
@@ -34267,10 +34502,10 @@ function ProgressPill({
34267
34502
  accessibilityLabel: t.nextPage,
34268
34503
  accessibilityState: { disabled: nextDisabled },
34269
34504
  disabled: nextDisabled,
34270
- onPress: () => pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34505
+ onPress: () => onTurnPage ? onTurnPage(1) : pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34271
34506
  style: styles21.pageArrowHit,
34272
34507
  testID: "papyrus-progress-page-next",
34273
- children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.pageArrow, isDark && styles21.labelDark, nextDisabled && styles21.pageArrowDisabled], children: "\u203A" })
34508
+ children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.pageArrow, isDark && styles21.labelDark, nextDisabled && styles21.pageArrowDisabled], children: "\u203A" })
34274
34509
  }
34275
34510
  )
34276
34511
  ] })
@@ -34411,11 +34646,14 @@ function ProgressPill({
34411
34646
  }
34412
34647
  const responderPanHandlers = scrubberResponderRef.current?.panHandlers ?? {};
34413
34648
  return /* @__PURE__ */ jsx25(
34414
- View21,
34649
+ Reanimated.View,
34415
34650
  {
34416
- pointerEvents: "box-none",
34651
+ pointerEvents: chromeVisible ? "box-none" : "none",
34652
+ accessibilityElementsHidden: !chromeVisible,
34653
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
34417
34654
  style: [
34418
34655
  styles21.frame,
34656
+ chromeMotion,
34419
34657
  resolvePageScrubberOverlayStyle(),
34420
34658
  {
34421
34659
  top: offsets.progress,
@@ -34466,7 +34704,7 @@ function ProgressPill({
34466
34704
  ...responderPanHandlers,
34467
34705
  testID: "papyrus-progress-pill",
34468
34706
  children: [
34469
- /* @__PURE__ */ jsx25(View21, { style: styles21.labelHit, children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: label }) }),
34707
+ /* @__PURE__ */ jsx25(View21, { style: styles21.labelHit, children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: label }) }),
34470
34708
  /* @__PURE__ */ jsx25(View21, { style: styles21.iconHit, children: /* @__PURE__ */ jsx25(
34471
34709
  IconPageNav,
34472
34710
  {
@@ -34597,7 +34835,7 @@ import {
34597
34835
  Keyboard,
34598
34836
  Pressable as Pressable14,
34599
34837
  StyleSheet as StyleSheet22,
34600
- Text as Text15,
34838
+ Text as Text16,
34601
34839
  TextInput as TextInput3,
34602
34840
  View as View22,
34603
34841
  useWindowDimensions as useWindowDimensions10
@@ -34730,7 +34968,7 @@ function SearchOverlay({
34730
34968
  onPress: handleClose,
34731
34969
  style: [styles22.closeButton, isDark && styles22.closeButtonDark],
34732
34970
  accessibilityLabel: "Close search",
34733
- children: /* @__PURE__ */ jsx26(Text15, { style: [styles22.closeText, isDark && styles22.closeTextDark], children: t.cancel })
34971
+ children: /* @__PURE__ */ jsx26(Text16, { style: [styles22.closeText, isDark && styles22.closeTextDark], children: t.cancel })
34734
34972
  }
34735
34973
  )
34736
34974
  ] }),
@@ -34749,7 +34987,7 @@ function SearchOverlay({
34749
34987
  children: /* @__PURE__ */ jsx26(IconChevronLeft, { size: 16, color: isDark ? "#e5e7eb" : "#111827" })
34750
34988
  }
34751
34989
  ),
34752
- /* @__PURE__ */ jsx26(Text15, { style: [styles22.metaText, isDark && styles22.metaTextDark], children: isSearching ? t.searching : `${currentCount}/${results.length} ${targetLabel}` }),
34990
+ /* @__PURE__ */ jsx26(Text16, { style: [styles22.metaText, isDark && styles22.metaTextDark], children: isSearching ? t.searching : `${currentCount}/${results.length} ${targetLabel}` }),
34753
34991
  /* @__PURE__ */ jsx26(
34754
34992
  Pressable14,
34755
34993
  {
@@ -34773,7 +35011,7 @@ function SearchOverlay({
34773
35011
  style: [styles22.primaryAction, { backgroundColor: accentColor }],
34774
35012
  accessibilityLabel: "Run search",
34775
35013
  testID: "papyrus-search-run",
34776
- children: /* @__PURE__ */ jsx26(Text15, { style: styles22.primaryActionText, children: t.searchGo })
35014
+ children: /* @__PURE__ */ jsx26(Text16, { style: styles22.primaryActionText, children: t.searchGo })
34777
35015
  }
34778
35016
  ),
34779
35017
  /* @__PURE__ */ jsx26(
@@ -34788,7 +35026,7 @@ function SearchOverlay({
34788
35026
  ],
34789
35027
  accessibilityLabel: "Open all results",
34790
35028
  children: /* @__PURE__ */ jsx26(
34791
- Text15,
35029
+ Text16,
34792
35030
  {
34793
35031
  style: [
34794
35032
  styles22.secondaryActionText,
@@ -34947,7 +35185,7 @@ var styles22 = StyleSheet22.create({
34947
35185
  });
34948
35186
 
34949
35187
  // components/SearchResultsSheet.tsx
34950
- import { Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text16 } from "react-native";
35188
+ import { Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text17 } from "react-native";
34951
35189
  import { useViewerStore as useViewerStore20 } from "@papyrus-sdk/core";
34952
35190
  import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
34953
35191
  function SearchResultsSheet({
@@ -34995,12 +35233,12 @@ function SearchResultsSheet({
34995
35233
  borderTopColor: palette.divider
34996
35234
  },
34997
35235
  children: [
34998
- /* @__PURE__ */ jsxs21(Text16, { style: [styles23.meta, { color: palette.mutedText }], children: [
35236
+ /* @__PURE__ */ jsxs21(Text17, { style: [styles23.meta, { color: palette.mutedText }], children: [
34999
35237
  results.length,
35000
35238
  " ",
35001
35239
  t.results
35002
35240
  ] }),
35003
- /* @__PURE__ */ jsx27(NativeSheetScrollView, { contentContainerStyle: styles23.content, children: results.length === 0 ? /* @__PURE__ */ jsx27(Text16, { style: [styles23.emptyText, { color: palette.mutedText }], children: t.noResults }) : results.map((result, index) => {
35241
+ /* @__PURE__ */ jsx27(NativeSheetScrollView, { contentContainerStyle: styles23.content, children: results.length === 0 ? /* @__PURE__ */ jsx27(Text17, { style: [styles23.emptyText, { color: palette.mutedText }], children: t.noResults }) : results.map((result, index) => {
35004
35242
  const isActive = index === activeSearchIndex;
35005
35243
  const isTextResult = "kind" in result && result.kind === "text";
35006
35244
  return /* @__PURE__ */ jsxs21(
@@ -35030,8 +35268,8 @@ function SearchResultsSheet({
35030
35268
  }
35031
35269
  ],
35032
35270
  children: [
35033
- /* @__PURE__ */ jsx27(Text16, { style: [styles23.resultLabel, { color: accentColor }], children: isTextResult ? getTextResultLabel(result.location.start) : getResultLabel(result.pageIndex) }),
35034
- /* @__PURE__ */ jsx27(Text16, { style: [styles23.resultText, { color: palette.text }], children: result.text })
35271
+ /* @__PURE__ */ jsx27(Text17, { style: [styles23.resultLabel, { color: accentColor }], children: isTextResult ? getTextResultLabel(result.location.start) : getResultLabel(result.pageIndex) }),
35272
+ /* @__PURE__ */ jsx27(Text17, { style: [styles23.resultText, { color: palette.text }], children: result.text })
35035
35273
  ]
35036
35274
  },
35037
35275
  isTextResult ? `text-${result.location.start}-${index}` : `page-${result.pageIndex}-${index}`
@@ -35152,15 +35390,10 @@ function ReadingShell({
35152
35390
  /* @__PURE__ */ jsx28(
35153
35391
  Topbar_default,
35154
35392
  {
35393
+ documentType,
35155
35394
  engine,
35156
35395
  title,
35157
- onOpenOverflow: () => {
35158
- closeMobileDestination();
35159
- setInfoOpen(false);
35160
- setActionsOpen(false);
35161
- setSettingsOpen(false);
35162
- setOverflowOpen(true);
35163
- },
35396
+ onOpenSettings: () => openDestination("display"),
35164
35397
  onOpenPageJump: () => setPageJumpOpen(true),
35165
35398
  showPageNavigationControls: false
35166
35399
  }
@@ -35168,6 +35401,7 @@ function ReadingShell({
35168
35401
  /* @__PURE__ */ jsx28(View23, { style: styles24.viewerStage, children: /* @__PURE__ */ jsx28(
35169
35402
  Viewer_default,
35170
35403
  {
35404
+ documentType,
35171
35405
  engine,
35172
35406
  ...viewerProps,
35173
35407
  pageScrubActive
@@ -35176,7 +35410,13 @@ function ReadingShell({
35176
35410
  /* @__PURE__ */ jsx28(
35177
35411
  ProgressPill,
35178
35412
  {
35413
+ navigationInDock: true,
35179
35414
  documentType,
35415
+ onTurnPage: documentType === "epub" ? (direction) => {
35416
+ const paginatedEngine = engine;
35417
+ void paginatedEngine.turnEpubPage?.(direction).catch(() => {
35418
+ });
35419
+ } : void 0,
35180
35420
  onNavigateToPage: navigateToPage,
35181
35421
  onPress: () => openDestination(
35182
35422
  documentType === "pdf" ? "pages" : documentType === "epub" ? "contents" : "progress"
@@ -35188,6 +35428,12 @@ function ReadingShell({
35188
35428
  /* @__PURE__ */ jsx28(
35189
35429
  BottomBar_default,
35190
35430
  {
35431
+ onNavigateToPage: navigateToPage,
35432
+ onOpenPages: () => setPageJumpOpen(true),
35433
+ onTurnPage: documentType === "epub" ? (direction) => {
35434
+ const paginatedEngine = engine;
35435
+ void paginatedEngine.turnEpubPage?.(direction).catch((error) => console.warn("[Papyrus] page navigation failed", error));
35436
+ } : void 0,
35191
35437
  documentType,
35192
35438
  onOpenDestination: openDestination,
35193
35439
  onOpenInfo: () => openDestination("info"),
@@ -35267,6 +35513,7 @@ function ReadingShell({
35267
35513
  /* @__PURE__ */ jsx28(
35268
35514
  SettingsSheet_default,
35269
35515
  {
35516
+ onOpenInfo: () => openDestination("info"),
35270
35517
  engine,
35271
35518
  documentType,
35272
35519
  visible: settingsOpen,
@@ -35279,6 +35526,7 @@ function ReadingShell({
35279
35526
  /* @__PURE__ */ jsx28(
35280
35527
  PageJumpModal,
35281
35528
  {
35529
+ documentType,
35282
35530
  visible: pageJumpOpen,
35283
35531
  currentPage,
35284
35532
  pageCount,