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

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,67 @@ 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,geometry){
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 atStart=Boolean(raw.atStart),atEnd=Boolean(raw.atEnd);
20533
+ // Chromium may round a column offset down by a fraction of a CSS pixel.
20534
+ // Keep epub.js authoritative outside a 1px boundary, and for RTL layouts.
20535
+ if(visualPage!==null && total>0 && geometry && geometry.direction==='ltr' && geometry.pageWidth>0 && Number.isFinite(geometry.offset)){
20536
+ var boundary=Math.round(geometry.offset/geometry.pageWidth);
20537
+ if(Math.abs(geometry.offset-boundary*geometry.pageWidth)<=1){
20538
+ visualPage=Math.min(total,Math.max(1,boundary+1));
20539
+ atStart=chapter===(geometry.firstIndex ?? 0)+1 && visualPage===1;
20540
+ atEnd=chapter===(geometry.lastIndex ?? count-1)+1 && visualPage===total;
20541
+ }
20542
+ }
20543
+ var fraction=total?Math.max(0,(visualPage-1)/total):0;
20544
+ 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:atStart,atEnd:atEnd};
20545
+ }
20546
+ function installResizeAnchor(manager,readCfi){
20547
+ var original=manager.resize,anchor=null;
20548
+ function resize(width,height,target){
20549
+ if(validCfi(target))anchor=target;
20550
+ if(!anchor){var current=readCfi();if(validCfi(current))anchor=current;}
20551
+ // epub.js accepts a logical target as its third argument. Keep it across
20552
+ // keyboard/dialog reflows instead of adopting each new viewport start.
20553
+ return original.call(this,width,height,anchor || target);
20554
+ }
20555
+ manager.resize=resize;
20556
+ return {cfi:function(){return anchor;},invalidate:function(){anchor=null;},destroy:function(){if(manager.resize===resize)manager.resize=original;anchor=null;}};
20557
+ }
20558
+ function install(contents,config){
20559
+ var doc=contents.document,win=contents.window,start=null,blocked=false;
20560
+ 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;}
20561
+ function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
20562
+ function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
20563
+ function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
20564
+ function invalidateScroll(finish){if(config.current() && start && finish && config.mode()==='chapter-scroll' && !blocked && !selected() && Math.abs(finish.y-start.y)>12 && Math.abs(finish.y-start.y)>Math.abs(finish.x-start.x) && config.interact)config.interact();}
20565
+ function move(e){if(e.touches.length!==1)blocked=true;invalidateScroll(point(e));}
20566
+ function end(e){var finish=point(e);invalidateScroll(finish);var action=gesture(start,finish,{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);}
20567
+ function cancel(){start=null;blocked=true;}
20568
+ function link(e){if(config.current() && e.target?.closest?.('a') && config.interact)config.interact();}
20569
+ doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});doc.addEventListener('click',link);
20570
+ return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);doc.removeEventListener('click',link);};
20571
+ }
20572
+ root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,installResizeAnchor:installResizeAnchor,install:install};
20573
+ })(typeof window==='undefined'?globalThis:window);
20574
+
20575
+ /* @papyrus-epub-reader:end */
20515
20576
  /* @papyrus-epub-annotations:start */
20516
20577
  (function (root, factory) {
20517
20578
  if (typeof module === 'object' && module.exports) module.exports = factory();
@@ -20590,6 +20651,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20590
20651
  var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
20591
20652
  var style = annotation.markupStyle || annotation.type;
20592
20653
  var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
20654
+ if(style === 'highlight')opacity=Math.min(0.35,opacity);
20593
20655
  rects.forEach(function(rect) {
20594
20656
  var mark = doc.createElement('div');
20595
20657
  var bodyRect=doc.body.getBoundingClientRect();
@@ -20602,8 +20664,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20602
20664
  if (hasNote) {
20603
20665
  var last = rects[rects.length-1], button = doc.createElement('button');
20604
20666
  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);
20667
+ var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
20668
+ var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
20669
+ 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';
20670
+ var key = column+":"+Math.floor(last.top/44);
20607
20671
  var neighbors=noteGroups.get(key);
20608
20672
  if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
20609
20673
  neighbors.ids.push(annotation.id);
@@ -20624,10 +20688,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20624
20688
  doc.addEventListener('click',tapMarkup);
20625
20689
  var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
20626
20690
  if (observer) observer.observe(doc.body);
20627
- win.addEventListener('resize',schedule); doc.addEventListener('load',schedule,true);
20691
+ win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
20628
20692
  if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
20629
20693
  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();}};
20694
+ 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
20695
  }
20632
20696
  return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
20633
20697
  });
@@ -20640,6 +20704,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20640
20704
  let currentType = null;
20641
20705
  let book = null;
20642
20706
  let rendition = null;
20707
+ let epubResizeAnchor = null;
20643
20708
  let documentSessionId = null;
20644
20709
  let annotationDocumentId;
20645
20710
  let annotationLabels = {};
@@ -21052,6 +21117,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21052
21117
  };
21053
21118
 
21054
21119
  const clearViewer = () => {
21120
+ if(epubResizeAnchor){epubResizeAnchor.destroy();epubResizeAnchor=null;}
21055
21121
  epubAnnotationRenderers.forEach(renderer => renderer.destroy());
21056
21122
  epubAnnotationRenderers.clear();
21057
21123
  if (epubInteractionCleanup) {
@@ -21708,26 +21774,57 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21708
21774
  pageCount,
21709
21775
  });
21710
21776
 
21777
+ if (book.locations?.generate) {
21778
+ const activeBook=book;
21779
+ activeBook.locations.generate(150).then(() => {
21780
+ if (isCurrentLoad() && activeBook===book && epubLocation) {
21781
+ epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
21782
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21783
+ }
21784
+ }).catch(() => {});
21785
+ }
21786
+ return renderEpubRendition(loadId,generation,null);
21787
+ };
21788
+
21789
+ const renderEpubRendition = async (loadId,generation,target) => {
21790
+ const diagnosticPayload={loadId};
21791
+ const isCurrentLoad=()=>generation===epubLoadGeneration;
21792
+ if(epubInteractionCleanup)epubInteractionCleanup();
21793
+ if(rendition)rendition.destroy();
21711
21794
  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
- });
21795
+ rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
21720
21796
  sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
21721
21797
 
21722
21798
  if (rendition && rendition.hooks && rendition.hooks.content) {
21723
21799
  const session = documentSessionId;
21724
21800
  const activeRendition = rendition;
21725
21801
  rendition.hooks.content.register((contents) => {
21802
+ const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
21803
+ mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
21804
+ rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
21805
+ blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
21806
+ annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
21807
+ current: () => session === documentSessionId && activeRendition === rendition,
21808
+ interact: () => epubResizeAnchor?.invalidate(),
21809
+ tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
21810
+ turn: direction => {
21811
+ epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
21812
+ if(session !== documentSessionId || activeRendition !== rendition)return;
21813
+ epubResizeAnchor?.invalidate();
21814
+ return direction<0?activeRendition.prev():activeRendition.next();
21815
+ });
21816
+ epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
21817
+ },
21818
+ });
21819
+ const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
21820
+ epubSelectionCleanups.add(gestureCleanup);
21821
+ contents.__papyrusGestureCleanup=gestureCleanup;
21726
21822
  const href = spineItems[contents.sectionIndex]?.href;
21727
21823
  if (href && window.PapyrusEpubAnnotations) {
21728
21824
  const renderer = window.PapyrusEpubAnnotations.install(contents, {
21729
21825
  href, get documentId() { return annotationDocumentId; },
21730
21826
  isCurrent: () => session === documentSessionId && activeRendition === rendition,
21827
+ pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
21731
21828
  annotations: () => epubAnnotations, labels: () => annotationLabels,
21732
21829
  onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
21733
21830
  });
@@ -21746,8 +21843,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21746
21843
  typeof selectionWindow.getSelection === 'function'
21747
21844
  ) {
21748
21845
  let selectionTimer = null;
21749
- let lastSelectionKey = '';
21750
- let lastSelectionAt = 0;
21846
+
21751
21847
  const reportSelection = () => {
21752
21848
  selectionTimer = null;
21753
21849
  if (session !== documentSessionId || activeRendition !== rendition) return;
@@ -21762,11 +21858,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21762
21858
  try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
21763
21859
  const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
21764
21860
  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;
21861
+ if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21770
21862
  const payload = {documentSessionId: session, text: anchor.quote,
21771
21863
  pageIndex: contents.sectionIndex + 1, anchor};
21772
21864
  nativeMenuSelection = {contents, payload};
@@ -21781,6 +21873,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21781
21873
  // The content document still emits selectionchange, so resolve its
21782
21874
  // live Range to a CFI before the native menu action can fire.
21783
21875
  if (text) reportSelection();
21876
+ else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
21784
21877
  };
21785
21878
  selectionDocument.addEventListener('selectionchange', handleSelectionChange);
21786
21879
  const selectionCleanup = () => {
@@ -21803,6 +21896,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21803
21896
  typeof rendition.hooks.unloaded.register === 'function'
21804
21897
  ) {
21805
21898
  rendition.hooks.unloaded.register((view) => {
21899
+ view?.contents?.__papyrusGestureCleanup?.();
21806
21900
  const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
21807
21901
  if (typeof cleanup === 'function') cleanup();
21808
21902
  const renderer = epubAnnotationRenderers.get(view?.contents);
@@ -21818,21 +21912,37 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21818
21912
  if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21819
21913
  const href = spineItems[contents.sectionIndex]?.href;
21820
21914
  const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
21821
- if (!anchor) return;
21915
+ if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21822
21916
  epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
21823
21917
  const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
21824
21918
  nativeMenuSelection = {contents, payload};
21825
21919
  sendEvent('EPUB_TEXT_SELECTED', payload);
21826
21920
  });
21827
- ['rendered','resized','layout'].forEach(name => rendition.on(name, () => {
21921
+ ['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
21828
21922
  if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
21829
21923
  }));
21830
21924
  rendition.on('relocated', (location) => {
21925
+ if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21831
21926
  const start = location && location.start;
21832
21927
  let index = start && Number.isInteger(start.index) ? start.index : -1;
21833
21928
  if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
21834
21929
  if (index < 0 || index >= spineItems.length) return;
21835
21930
  epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
21931
+ let pageGeometry;
21932
+ const manager=rendition.manager,layout=manager?.layout;
21933
+ if(epubViewMode==='single' && layout?.divisor===1 && !manager?.settings?.fullsize && manager?.settings?.direction==='ltr'){
21934
+ const visible=manager.visible?.();
21935
+ const view=visible?.find(view=>view.index===index);
21936
+ if(view && manager.container){
21937
+ pageGeometry={direction:'ltr',firstIndex:book.spine.first()?.index,lastIndex:book.spine.last()?.index,pageWidth:layout.pageWidth,offset:manager.container.getBoundingClientRect().left-view.position().left};
21938
+ }
21939
+ }
21940
+ epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll',pageGeometry);
21941
+ if(epubLocation){
21942
+ epubLocation.cfi=epubResizeAnchor?.cfi() || epubLocation.cfi;
21943
+ if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
21944
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21945
+ }
21836
21946
  const nextPage = index + 1;
21837
21947
  if (nextPage === currentPage) return;
21838
21948
  currentPage = nextPage;
@@ -21840,21 +21950,23 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21840
21950
  });
21841
21951
  }
21842
21952
 
21953
+ applyEpubZoom();
21843
21954
  sendEpubDiagnostic('epub.display.start', diagnosticPayload);
21844
21955
  await withEpubStageTimeout(
21845
- displayEpubPage(0),
21956
+ rendition.display(target || spineItems[0]?.href),
21846
21957
  'rendition.display',
21847
21958
  diagnosticPayload,
21848
21959
  );
21849
21960
  if (!isCurrentLoad()) throw new Error('EPUB load superseded by a newer load');
21850
21961
  sendEpubDiagnostic('epub.display.end', diagnosticPayload);
21962
+ const resizeRendition=rendition;
21963
+ epubResizeAnchor=window.PapyrusEpubReader.installResizeAnchor(resizeRendition.manager,()=>resizeRendition.location?.start?.cfi);
21851
21964
  if (
21852
21965
  rendition &&
21853
21966
  rendition.manager &&
21854
21967
  typeof rendition.manager.on === 'function' &&
21855
21968
  typeof rendition.on === 'function'
21856
21969
  ) {
21857
- let touchStart = null;
21858
21970
  let lastScrollOffset = -1;
21859
21971
  const manager = rendition.manager;
21860
21972
  epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
@@ -21929,48 +22041,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21929
22041
  return result;
21930
22042
  };
21931
22043
  }
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) => {
22044
+ const handleScroll = event => {
21942
22045
  const offsetY = Math.max(0, Number(event && event.top) || 0);
21943
22046
  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);
22047
+ if (Math.abs(offsetY-lastScrollOffset)<1) return;
22048
+ lastScrollOffset=offsetY;
22049
+ sendEvent('VIEWER_SCROLL',{offsetY});
21964
22050
  };
21965
-
21966
22051
  manager.on('scroll', handleScroll);
21967
22052
  const handleScrolled = (event) => {
21968
22053
  epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
21969
22054
  };
21970
22055
  manager.on('scrolled', handleScrolled);
21971
- rendition.on('touchstart', handleTouchStart);
21972
- rendition.on('touchmove', handleTouchMove);
21973
- rendition.on('touchend', handleTouchEnd);
22056
+
21974
22057
  epubInteractionCleanup = () => {
21975
22058
  epubSelectionCleanups.forEach((cleanup) => cleanup());
21976
22059
  epubSelectionCleanups.clear();
@@ -21979,16 +22062,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21979
22062
  if (originalEnqueue) queue.enqueue = originalEnqueue;
21980
22063
  if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
21981
22064
  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
22065
  epubScrollDiagnostics = null;
21988
22066
  };
21989
22067
  }
21990
- applyEpubZoom();
21991
-
21992
22068
  const outline = await withEpubStageTimeout(
21993
22069
  buildOutline(),
21994
22070
  'outline',
@@ -22002,6 +22078,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22002
22078
  return { pageCount, outline };
22003
22079
  };
22004
22080
 
22081
+ let epubNavigationQueue = Promise.resolve();
22082
+ let epubNavigationRequest = 0;
22005
22083
  const displayEpubPage = async (pageIndex) => {
22006
22084
  if (!rendition) return;
22007
22085
  const item = spineItems[pageIndex];
@@ -22011,9 +22089,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22011
22089
  target,
22012
22090
  pageIndex,
22013
22091
  });
22014
- await rendition.display(target);
22015
- currentPage = pageIndex + 1;
22016
- sendState();
22092
+ const activeRendition = rendition;
22093
+ const session = documentSessionId;
22094
+ const request = ++epubNavigationRequest;
22095
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22096
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22097
+ epubResizeAnchor?.invalidate();
22098
+ await activeRendition.display(target);
22099
+ if (request !== epubNavigationRequest || session !== documentSessionId || activeRendition !== rendition) return;
22100
+ currentPage = pageIndex + 1;
22101
+ sendState();
22102
+ });
22103
+ epubNavigationQueue = navigation;
22104
+ await navigation;
22017
22105
  };
22018
22106
 
22019
22107
  const getTextContent = async (pageIndex) => {
@@ -22115,6 +22203,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22115
22203
  };
22116
22204
 
22117
22205
  let nativeMenuSelection = null;
22206
+ let epubViewMode = "single";
22207
+ let epubLocation = null;
22118
22208
 
22119
22209
  const handleCommand = async (message) => {
22120
22210
  const { id, kind, payload } = message;
@@ -22127,6 +22217,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22127
22217
  epubAnnotations = [];
22128
22218
  annotationDocumentId = undefined;
22129
22219
  zoom = 1.0;
22220
+ epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
22221
+ epubLocation = null;
22222
+ nativeMenuSelection = null;
22223
+ epubNavigationRequest += 1;
22224
+ epubNavigationQueue = Promise.resolve();
22130
22225
 
22131
22226
  if (currentType === 'text') {
22132
22227
  const result = await loadText(
@@ -22181,17 +22276,24 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22181
22276
  epubAnnotationRenderers.forEach(renderer => renderer.schedule());
22182
22277
  } else {
22183
22278
  const annotation = epubAnnotations.find(a => a.id === payload.annotationId);
22184
- if (!annotation) throw new Error('Annotation not available');
22279
+ if (!annotation || (annotation.anchor.documentId && annotation.anchor.documentId !== annotationDocumentId)) throw new Error('Annotation not available for this document');
22185
22280
  // Navigation uses the CFI, never a synthetic percentage/page rectangle.
22186
22281
  const navigationSession = documentSessionId;
22187
22282
  const activeRendition = rendition;
22188
22283
  // 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));
22284
+ epubNavigationRequest += 1;
22285
+ const navigation = epubNavigationQueue.catch(() => {}).then(async () => {
22286
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22287
+ epubResizeAnchor?.invalidate();
22288
+ await activeRendition.display(annotation.anchor.href);
22289
+ if(navigationSession !== documentSessionId || activeRendition !== rendition)throw new Error('Stale EPUB navigation');
22290
+ const contents = activeRendition.getContents().find(c => spineItems[c.sectionIndex]?.href === annotation.anchor.href);
22291
+ const range = contents && window.PapyrusEpubAnnotations.resolveRange(contents,annotation.anchor);
22292
+ if(!range)throw new Error('EPUB anchor unresolved');
22293
+ await activeRendition.display(contents.cfiFromRange(range));
22294
+ });
22295
+ epubNavigationQueue = navigation;
22296
+ await navigation;
22195
22297
  }
22196
22298
  sendResponse(id,true,null); return;
22197
22299
  }
@@ -22218,12 +22320,55 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22218
22320
  return;
22219
22321
  }
22220
22322
 
22323
+ if (kind === 'epub-turn-page') {
22324
+ if (epubViewMode !== 'single') {sendResponse(id,true,null); return;}
22325
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB navigation');
22326
+ const active = rendition;
22327
+ epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22328
+ if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22329
+ epubResizeAnchor?.invalidate();
22330
+ return payload.direction < 0 ? active.prev() : active.next();
22331
+ });
22332
+ await epubNavigationQueue;
22333
+ sendResponse(id,true,null); return;
22334
+ }
22335
+
22336
+ if (kind === 'set-epub-view-mode') {
22337
+ if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
22338
+ const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
22339
+ {
22340
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22341
+ if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
22342
+ const target=epubResizeAnchor?.cfi() || epubLocation?.cfi;
22343
+ epubViewMode=next;
22344
+ await renderEpubRendition('layout',epubLoadGeneration,target);
22345
+ });
22346
+ await epubNavigationQueue;
22347
+ }
22348
+ sendResponse(id,true,null);return;
22349
+ }
22350
+ if(kind === 'epub-go-to-location'){
22351
+ if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
22352
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>{if(payload.documentSessionId!==documentSessionId)return;epubResizeAnchor?.invalidate();return rendition.display(payload.cfi);});
22353
+ await epubNavigationQueue;sendResponse(id,true,null);return;
22354
+ }
22355
+
22221
22356
  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;
22357
+ const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
22358
+ if(currentType === 'epub') {
22359
+ const session=documentSessionId;
22360
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22361
+ if(session!==documentSessionId)return;
22362
+ const active=rendition;
22363
+ const cfi=epubResizeAnchor?.cfi() || epubLocation?.cfi;
22364
+ zoom=requestedZoom;applyEpubZoom();
22365
+ // Let the content CSS update before redisplaying the logical anchor.
22366
+ await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
22367
+ if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
22368
+ });
22369
+ await epubNavigationQueue;
22370
+ } else {zoom=requestedZoom;applyZoom();}
22371
+ sendState();sendResponse(id,true,{zoom});return;
22227
22372
  }
22228
22373
 
22229
22374
  if (kind === 'set-rotation') {
@@ -23399,6 +23544,7 @@ var IconToolStrikeout = ({
23399
23544
  ),
23400
23545
  /* @__PURE__ */ jsx2(Rect, { x: "10.9", y: "17.1", width: "14.2", height: "2.4", rx: "1.2", fill: color })
23401
23546
  ] });
23547
+ 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
23548
  var IconCopy = ({
23403
23549
  size = 20,
23404
23550
  color = defaultColor,
@@ -23463,6 +23609,39 @@ var IconToolNote = ({
23463
23609
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "14.8", x2: "21.6", y2: "14.8", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" }),
23464
23610
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "18.2", x2: "19.2", y2: "18.2", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" })
23465
23611
  ] });
23612
+ var IconHighlight = ({
23613
+ size = 24,
23614
+ color = "#fbbf24"
23615
+ }) => /* @__PURE__ */ jsxs(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
23616
+ /* @__PURE__ */ jsx2(
23617
+ Path,
23618
+ {
23619
+ d: "M4 15h16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3Z",
23620
+ fill: color,
23621
+ opacity: "0.85"
23622
+ }
23623
+ ),
23624
+ /* @__PURE__ */ jsx2(
23625
+ Path,
23626
+ {
23627
+ d: "M6 5h12v10H6V5Z",
23628
+ stroke: color,
23629
+ strokeWidth: "2",
23630
+ strokeLinecap: "round",
23631
+ strokeLinejoin: "round",
23632
+ fill: "none"
23633
+ }
23634
+ ),
23635
+ /* @__PURE__ */ jsx2(
23636
+ Path,
23637
+ {
23638
+ d: "M8 8h8M8 11h5",
23639
+ stroke: color,
23640
+ strokeWidth: "2",
23641
+ strokeLinecap: "round"
23642
+ }
23643
+ )
23644
+ ] });
23466
23645
  var IconUnderline = ({
23467
23646
  size = 24,
23468
23647
  color = "#60a5fa",
@@ -25673,6 +25852,39 @@ var styles = StyleSheet.create({
25673
25852
  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
25853
  var PageRenderer_default = memo(PageRenderer, arePageRendererPropsEqual);
25675
25854
 
25855
+ // components/PapyrusSafeArea.tsx
25856
+ import React3, { useContext as useContext2 } from "react";
25857
+ import {
25858
+ SafeAreaInsetsContext,
25859
+ SafeAreaProvider
25860
+ } from "react-native-safe-area-context";
25861
+ import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
25862
+ var papyrusSafeAreaContext = SafeAreaInsetsContext;
25863
+ var ZERO_SAFE_AREA_INSETS = {
25864
+ top: 0,
25865
+ bottom: 0,
25866
+ left: 0,
25867
+ right: 0
25868
+ };
25869
+ var usePapyrusSafeAreaInsets = () => useContext2(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
25870
+ function PapyrusSafeAreaBoundary({
25871
+ children
25872
+ }) {
25873
+ const insets = useContext2(papyrusSafeAreaContext);
25874
+ if (insets) return /* @__PURE__ */ jsx4(Fragment, { children });
25875
+ return React3.createElement(SafeAreaProvider, null, children);
25876
+ }
25877
+
25878
+ // components/epubReadingLocation.ts
25879
+ function parseEpubReadingLocation(raw) {
25880
+ if (!raw || typeof raw !== "object") return null;
25881
+ const p = raw;
25882
+ 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;
25883
+ if (p.mode === "chapter-scroll") return p.visualPage === null && p.visualPageCount === null ? p : null;
25884
+ if (p.mode !== "paged" || !Number.isSafeInteger(p.visualPage) || (p.visualPage ?? 0) < 1 || !Number.isSafeInteger(p.visualPageCount) || (p.visualPageCount ?? 0) < (p.visualPage ?? 0)) return null;
25885
+ return p;
25886
+ }
25887
+
25676
25888
  // components/WebViewViewer.tsx
25677
25889
  import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
25678
25890
  import { Image, StyleSheet as StyleSheet2, View as View2, Alert } from "react-native";
@@ -25742,7 +25954,7 @@ function parseEpubAnnotationEvent(raw, session, documentId) {
25742
25954
  }
25743
25955
 
25744
25956
  // components/WebViewViewer.tsx
25745
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
25957
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
25746
25958
  var runtimeAsset = require_runtime();
25747
25959
  var resolveRuntimeSource = (asset) => {
25748
25960
  if (typeof asset === "string") {
@@ -25762,6 +25974,7 @@ var resolveRuntimeSource = (asset) => {
25762
25974
  };
25763
25975
  var WebViewViewer = ({
25764
25976
  engine,
25977
+ documentType,
25765
25978
  documentId,
25766
25979
  onDefineSelection,
25767
25980
  defineSelectionMode,
@@ -25770,7 +25983,8 @@ var WebViewViewer = ({
25770
25983
  onTap
25771
25984
  }) => {
25772
25985
  const webViewRef = useRef2(null);
25773
- const { pageTheme, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25986
+ const insets = usePapyrusSafeAreaInsets();
25987
+ const { pageTheme, epubReadingMode, setDocumentState, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25774
25988
  const [selection, setSelection] = useState2(null);
25775
25989
  const t = getStrings(locale);
25776
25990
  const bridgeEngine = engine;
@@ -25851,6 +26065,10 @@ var WebViewViewer = ({
25851
26065
  (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
26066
  setSelection(null);
25853
26067
  };
26068
+ useEffect2(() => {
26069
+ if (!isLoaded) return;
26070
+ webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { epubMode: epubReadingMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26071
+ }, [isLoaded, epubReadingMode, bridgeEngine]);
25854
26072
  const sendSelectionCommand = (key) => {
25855
26073
  webViewRef.current?.postMessage(JSON.stringify({
25856
26074
  type: "epub-selection-action",
@@ -25874,6 +26092,11 @@ var WebViewViewer = ({
25874
26092
  let annotationRaw = raw;
25875
26093
  try {
25876
26094
  const message = JSON.parse(raw);
26095
+ if (message.type === "event" && message.name === "EPUB_LOCATION" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) {
26096
+ const location = parseEpubReadingLocation(message.payload.location);
26097
+ if (location) setDocumentState({ epubLocation: location });
26098
+ }
26099
+ if (message.type === "event" && message.name === "EPUB_CONTENT_TAP" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) onTap?.();
25877
26100
  if (message.type === "event" && message.name === "EPUB_SELECTION_ACTION") {
25878
26101
  action = message.payload?.action;
25879
26102
  annotationRaw = JSON.stringify({ ...message, name: "EPUB_TEXT_SELECTED" });
@@ -25962,8 +26185,8 @@ var WebViewViewer = ({
25962
26185
  maxWidth: resolvedMaxPageWidth,
25963
26186
  alignSelf: "center"
25964
26187
  } : void 0;
25965
- return /* @__PURE__ */ jsxs3(View2, { style: styles2.container, children: [
25966
- /* @__PURE__ */ jsx4(
26188
+ return /* @__PURE__ */ jsxs3(View2, { style: [styles2.container, documentType === "epub" && { paddingTop: insets.top, paddingBottom: insets.bottom }], children: [
26189
+ /* @__PURE__ */ jsx5(
25967
26190
  WebView,
25968
26191
  {
25969
26192
  ref: webViewRef,
@@ -25987,7 +26210,7 @@ var WebViewViewer = ({
25987
26210
  style: [styles2.webview, cappedWebViewStyle]
25988
26211
  }
25989
26212
  ),
25990
- /* @__PURE__ */ jsx4(
26213
+ /* @__PURE__ */ jsx5(
25991
26214
  View2,
25992
26215
  {
25993
26216
  pointerEvents: "none",
@@ -26089,16 +26312,16 @@ function getNearbyPdfNotes(annotations, id) {
26089
26312
  // components/PdfNoteChooser.tsx
26090
26313
  import { FlatList, Modal, Pressable as Pressable2, StyleSheet as StyleSheet3, Text, View as View3 } from "react-native";
26091
26314
  import { getAnnotationNote, getAnnotationQuote } from "@papyrus-sdk/core";
26092
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
26315
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
26093
26316
  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: [
26317
+ 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: [
26318
+ /* @__PURE__ */ jsx6(Text, { style: styles3.title, children: title }),
26319
+ /* @__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
26320
  index + 1,
26098
26321
  ". ",
26099
26322
  getAnnotationNote(item) || getAnnotationQuote(item)
26100
26323
  ] }) }) }),
26101
- /* @__PURE__ */ jsx5(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx5(Text, { children: cancel }) })
26324
+ /* @__PURE__ */ jsx6(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx6(Text, { children: cancel }) })
26102
26325
  ] }) }) });
26103
26326
  }
26104
26327
  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 +26348,7 @@ var resolvePageTapChromeVisibility = ({
26125
26348
  };
26126
26349
 
26127
26350
  // components/DedicatedAndroidPdfViewer.tsx
26128
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
26351
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
26129
26352
  var TEXT_MARKUP_TOOLS2 = /* @__PURE__ */ new Set(["highlight", "underline", "squiggly", "strikeout"]);
26130
26353
  var MOBILE_CHROME_HIDE_DELTA = 28;
26131
26354
  var MOBILE_CHROME_SHOW_DELTA = 22;
@@ -26269,11 +26492,11 @@ function DedicatedAndroidPdfViewer({
26269
26492
  selectionRef.current = null;
26270
26493
  }, [addAnnotation, beginAnnotationDraft, annotationColor, documentId]);
26271
26494
  return /* @__PURE__ */ jsxs5(View4, { style: styles4.container, children: [
26272
- /* @__PURE__ */ jsx6(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26495
+ /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26273
26496
  setPendingNotes([]);
26274
26497
  setSelectedAnnotation(id);
26275
26498
  } }),
26276
- /* @__PURE__ */ jsx6(
26499
+ /* @__PURE__ */ jsx7(
26277
26500
  PapyrusPdfDocumentView,
26278
26501
  {
26279
26502
  style: [styles4.viewer, cappedViewerStyle],
@@ -26484,7 +26707,7 @@ var resolveNativePdfVisiblePages = (pages) => (pages ?? []).flatMap((page) => {
26484
26707
  });
26485
26708
 
26486
26709
  // components/DedicatedIosPdfViewer.tsx
26487
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
26710
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
26488
26711
  var MOBILE_CHROME_HIDE_DELTA2 = 28;
26489
26712
  var MOBILE_CHROME_SHOW_DELTA2 = 22;
26490
26713
  var MOBILE_CHROME_SHOW_DELAY_MS2 = 180;
@@ -26723,11 +26946,11 @@ function DedicatedIosPdfViewer({
26723
26946
  alignSelf: "center"
26724
26947
  } : void 0;
26725
26948
  return /* @__PURE__ */ jsxs6(View5, { style: styles5.container, children: [
26726
- /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26949
+ /* @__PURE__ */ jsx8(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26727
26950
  setPendingNotes([]);
26728
26951
  setSelectedAnnotation(id);
26729
26952
  } }),
26730
- /* @__PURE__ */ jsx7(
26953
+ /* @__PURE__ */ jsx8(
26731
26954
  PapyrusPdfDocumentView2,
26732
26955
  {
26733
26956
  style: [styles5.viewer, cappedViewerStyle],
@@ -26796,22 +27019,22 @@ function DedicatedIosPdfViewer({
26796
27019
  onInkToolPickerVisibilityChange: handleInkToolPickerVisibilityChange
26797
27020
  }
26798
27021
  ),
26799
- selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx7(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx7(
27022
+ selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx8(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx8(
26800
27023
  Pressable3,
26801
27024
  {
26802
27025
  onPress: defineSelection,
26803
27026
  style: styles5.fallbackButton,
26804
27027
  accessibilityRole: "button",
26805
27028
  accessibilityLabel: t.define,
26806
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.fallbackButtonText, children: t.define })
27029
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.fallbackButtonText, children: t.define })
26807
27030
  }
26808
27031
  ) }),
26809
- fallbackDeleteAnnotation && /* @__PURE__ */ jsx7(
27032
+ fallbackDeleteAnnotation && /* @__PURE__ */ jsx8(
26810
27033
  View5,
26811
27034
  {
26812
27035
  style: styles5.annotationDeleteFallback,
26813
27036
  pointerEvents: "box-none",
26814
- children: /* @__PURE__ */ jsx7(
27037
+ children: /* @__PURE__ */ jsx8(
26815
27038
  Pressable3,
26816
27039
  {
26817
27040
  onPress: () => handleDeleteAnnotation(fallbackDeleteAnnotation.id),
@@ -26819,7 +27042,7 @@ function DedicatedIosPdfViewer({
26819
27042
  accessibilityRole: "button",
26820
27043
  accessibilityLabel: t.deleteAnnotation,
26821
27044
  hitSlop: 8,
26822
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
27045
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
26823
27046
  }
26824
27047
  )
26825
27048
  }
@@ -26882,7 +27105,7 @@ var styles5 = StyleSheet5.create({
26882
27105
  });
26883
27106
 
26884
27107
  // components/NativePdfDocumentViewer.tsx
26885
- import { jsx as jsx8 } from "react/jsx-runtime";
27108
+ import { jsx as jsx9 } from "react/jsx-runtime";
26886
27109
  function NativePdfDocumentViewer({
26887
27110
  engine,
26888
27111
  documentId,
@@ -26895,7 +27118,7 @@ function NativePdfDocumentViewer({
26895
27118
  Platform3.OS
26896
27119
  );
26897
27120
  if (implementation === "android") {
26898
- return /* @__PURE__ */ jsx8(
27121
+ return /* @__PURE__ */ jsx9(
26899
27122
  DedicatedAndroidPdfViewer,
26900
27123
  {
26901
27124
  engine,
@@ -26908,7 +27131,7 @@ function NativePdfDocumentViewer({
26908
27131
  );
26909
27132
  }
26910
27133
  if (implementation === "ios") {
26911
- return /* @__PURE__ */ jsx8(
27134
+ return /* @__PURE__ */ jsx9(
26912
27135
  DedicatedIosPdfViewer,
26913
27136
  {
26914
27137
  engine,
@@ -26964,29 +27187,6 @@ var resolveMobileChromeOffsets = (insets) => ({
26964
27187
  right: MOBILE_CHROME_METRICS.screenPadding + Math.max(0, insets.right)
26965
27188
  });
26966
27189
 
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
27190
  // components/NativeTextDocumentViewer.tsx
26991
27191
  import { jsx as jsx10 } from "react/jsx-runtime";
26992
27192
  function NativeTextDocumentViewer({
@@ -27537,6 +27737,7 @@ var scrollViewerListToOffset = (list, offset, animated) => {
27537
27737
  list.scrollToOffset?.({ offset, animated });
27538
27738
  };
27539
27739
  var Viewer = ({
27740
+ documentType,
27540
27741
  documentId,
27541
27742
  engine,
27542
27743
  maxPageWidth,
@@ -29064,14 +29265,8 @@ var Viewer = ({
29064
29265
  },
29065
29266
  [mobilePerf, perfEnabled, scrollPerfSession]
29066
29267
  );
29067
- const handleWebViewScroll = useCallback4(
29068
- (_offsetY) => {
29069
- if (!chromeVisibleRef.current) {
29070
- setMobileChromeVisible(true, "scroll.webview.recover");
29071
- }
29072
- },
29073
- [setMobileChromeVisible]
29074
- );
29268
+ const handleWebViewScroll = useCallback4((_offsetY) => {
29269
+ }, []);
29075
29270
  const handlePageTap = useCallback4(() => {
29076
29271
  const nextVisible = resolvePageTapChromeVisibility({
29077
29272
  chromeVisible: chromeVisibleRef.current,
@@ -29293,6 +29488,7 @@ var Viewer = ({
29293
29488
  return /* @__PURE__ */ jsx12(View8, { style: [styles8.container, isDark && styles8.containerDark], children: /* @__PURE__ */ jsx12(
29294
29489
  WebViewViewer_default,
29295
29490
  {
29491
+ documentType,
29296
29492
  engine,
29297
29493
  documentId,
29298
29494
  onDefineSelection,
@@ -29499,7 +29695,8 @@ import {
29499
29695
  Text as Text5,
29500
29696
  Pressable as Pressable6,
29501
29697
  StyleSheet as StyleSheet11,
29502
- useWindowDimensions as useWindowDimensions4
29698
+ useWindowDimensions as useWindowDimensions4,
29699
+ Platform as Platform6
29503
29700
  } from "react-native";
29504
29701
  import { useViewerStore as useViewerStore9 } from "@papyrus-sdk/core";
29505
29702
  import Animated3, { useAnimatedStyle } from "react-native-reanimated";
@@ -29862,6 +30059,7 @@ var styles9 = StyleSheet9.create({
29862
30059
  // components/PageJumpModal.tsx
29863
30060
  import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
29864
30061
  function PageJumpModal({
30062
+ documentType,
29865
30063
  visible,
29866
30064
  currentPage,
29867
30065
  pageCount,
@@ -29888,8 +30086,8 @@ function PageJumpModal({
29888
30086
  isDark,
29889
30087
  maxHeight: 300,
29890
30088
  showHeader: true,
29891
- title: "Ir para p\xE1gina",
29892
- closeAccessibilityLabel: "Close page jump",
30089
+ title: documentType === "epub" ? "Ir para cap\xEDtulo" : "Ir para p\xE1gina",
30090
+ closeAccessibilityLabel: "Fechar navega\xE7\xE3o",
29893
30091
  sheetStyle: {
29894
30092
  paddingHorizontal: 18,
29895
30093
  paddingBottom: 18,
@@ -29917,7 +30115,7 @@ function PageJumpModal({
29917
30115
  }
29918
30116
  ],
29919
30117
  onSubmitEditing: confirmJump,
29920
- accessibilityLabel: "Page jump input",
30118
+ accessibilityLabel: documentType === "epub" ? "N\xFAmero do cap\xEDtulo" : "N\xFAmero da p\xE1gina",
29921
30119
  testID: "papyrus-page-jump-input"
29922
30120
  }
29923
30121
  ),
@@ -29972,6 +30170,7 @@ var styles10 = StyleSheet10.create({
29972
30170
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
29973
30171
  var Topbar = ({
29974
30172
  engine,
30173
+ documentType,
29975
30174
  onOpenSettings,
29976
30175
  onOpenOverflow,
29977
30176
  title,
@@ -29992,6 +30191,12 @@ var Topbar = ({
29992
30191
  locale
29993
30192
  } = useViewerStore9();
29994
30193
  const inkSession = useNativeInkSession();
30194
+ const chromeVisible = mobileChromeVisible || inkSession.active;
30195
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
30196
+ const chromeMotion = useAnimatedStyle(() => {
30197
+ "worklet";
30198
+ return { opacity: chromeProgress.value };
30199
+ });
29995
30200
  const t = getStrings(locale);
29996
30201
  const progress = useNativeInkMotion(inkSession.active, inkSession.supported);
29997
30202
  const settingsMotion = useAnimatedStyle(() => {
@@ -30047,26 +30252,30 @@ var Topbar = ({
30047
30252
  children: /* @__PURE__ */ jsx15(IconSettings, { size: MOBILE_CHROME_METRICS.iconSize, color: isDark ? "#e5e7eb" : "#111827" })
30048
30253
  }
30049
30254
  );
30050
- if (!mobileChromeVisible && !inkSession.active) return null;
30255
+ if (!chromeVisible && documentType !== "epub") return null;
30051
30256
  return /* @__PURE__ */ jsxs10(Fragment2, { children: [
30052
30257
  /* @__PURE__ */ jsx15(
30053
- View11,
30258
+ Animated3.View,
30054
30259
  {
30055
30260
  style: [
30056
30261
  styles11.chromeFrame,
30262
+ chromeMotion,
30057
30263
  {
30058
30264
  paddingTop: insets.top,
30059
30265
  paddingLeft: MOBILE_CHROME_METRICS.screenPadding + insets.left,
30060
30266
  paddingRight: MOBILE_CHROME_METRICS.screenPadding + insets.right
30061
30267
  }
30062
30268
  ],
30063
- pointerEvents: "box-none",
30269
+ pointerEvents: chromeVisible ? "box-none" : "none",
30270
+ accessibilityElementsHidden: !chromeVisible,
30271
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
30064
30272
  testID: "papyrus-floating-top-controls",
30065
30273
  children: /* @__PURE__ */ jsxs10(
30066
30274
  View11,
30067
30275
  {
30068
30276
  style: [
30069
30277
  styles11.container,
30278
+ Platform6.OS === "ios" && styles11.containerIos,
30070
30279
  isDark && styles11.containerDark,
30071
30280
  isLandscape && styles11.containerLandscape
30072
30281
  ],
@@ -30206,6 +30415,7 @@ var Topbar = ({
30206
30415
  /* @__PURE__ */ jsx15(
30207
30416
  PageJumpModal,
30208
30417
  {
30418
+ documentType,
30209
30419
  visible: jumpModalOpen,
30210
30420
  currentPage,
30211
30421
  pageCount,
@@ -30223,7 +30433,8 @@ var styles11 = StyleSheet11.create({
30223
30433
  maxWidth: MOBILE_CHROME_METRICS.maxFloatingWidth,
30224
30434
  marginTop: 10,
30225
30435
  paddingHorizontal: 14,
30226
- paddingVertical: 10,
30436
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30437
+ paddingVertical: 0,
30227
30438
  backgroundColor: "rgba(255,255,255,0.88)",
30228
30439
  borderWidth: 1,
30229
30440
  borderColor: "rgba(255,255,255,0.72)",
@@ -30240,6 +30451,10 @@ var styles11 = StyleSheet11.create({
30240
30451
  backgroundColor: "rgba(15,17,21,0.88)",
30241
30452
  borderColor: "rgba(71,85,105,0.48)"
30242
30453
  },
30454
+ containerIos: {
30455
+ height: MOBILE_CHROME_METRICS.topbarHeight,
30456
+ paddingVertical: 0
30457
+ },
30243
30458
  containerLandscape: {
30244
30459
  maxWidth: void 0,
30245
30460
  marginTop: 0
@@ -31389,7 +31604,7 @@ import {
31389
31604
  } from "react";
31390
31605
  import {
31391
31606
  Image as Image2,
31392
- Platform as Platform6,
31607
+ Platform as Platform7,
31393
31608
  Pressable as Pressable8,
31394
31609
  StyleSheet as StyleSheet13,
31395
31610
  Text as Text7,
@@ -31470,7 +31685,7 @@ var PageThumbnail = ({
31470
31685
  if (!layoutReady || !useNativePreview || !shouldRenderPreview) return;
31471
31686
  const viewTag = findNodeHandle2(viewRef.current);
31472
31687
  if (!viewTag) return;
31473
- const isNative = Platform6.OS === "android" || Platform6.OS === "ios";
31688
+ const isNative = Platform7.OS === "android" || Platform7.OS === "ios";
31474
31689
  const renderScale = isNative ? 2 / Math.max(zoom, 0.5) : 2;
31475
31690
  void engine.renderPage(pageIndex, viewTag, renderScale);
31476
31691
  }, [
@@ -32395,14 +32610,14 @@ var RightSheet_default = RightSheet;
32395
32610
 
32396
32611
  // components/AnnotationEditor.tsx
32397
32612
  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";
32613
+ 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
32614
  import { getAnnotationEditPatch, getAnnotationMarkup as getAnnotationMarkup2, getAnnotationNote as getAnnotationNote2, getAnnotationQuote as getAnnotationQuote2, useViewerStore as useViewerStore12 } from "@papyrus-sdk/core";
32400
32615
  import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
32401
32616
  var COLORS = ["#fbbf24", "#fb7185", "#60a5fa", "#34d399", "#c084fc"];
32402
- var AnnotationEditor = () => {
32617
+ var AnnotationEditor = ({ documentId }) => {
32403
32618
  const { annotations, annotationDraft, clearAnnotationDraft, addAnnotation, selectedAnnotationId, updateAnnotation, removeAnnotation, setSelectedAnnotation, uiTheme, locale, accentColor } = useViewerStore12();
32404
32619
  const annotation = annotationDraft?.id === selectedAnnotationId ? annotationDraft : annotations.find((a) => a.id === selectedAnnotationId);
32405
- const supported = annotation && annotation.type !== "ink";
32620
+ const supported = annotation && annotation.type !== "ink" && (!documentId || !annotation.anchor?.documentId || annotation.anchor.documentId === documentId);
32406
32621
  const [editing, setEditing] = useState12(false);
32407
32622
  const [draft, setDraft] = useState12("");
32408
32623
  const [color, setColor] = useState12(COLORS[0]);
@@ -32462,19 +32677,39 @@ var AnnotationEditor = () => {
32462
32677
  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
32678
  const textStyle = { color: dark ? "#f9fafb" : "#111827" };
32464
32679
  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: [
32680
+ 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
32681
  /* @__PURE__ */ jsx18(Pressable9, { style: StyleSheet14.absoluteFill, onPress: close, accessibilityLabel: t.close }),
32467
32682
  /* @__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
32683
  /* @__PURE__ */ jsxs13(View14, { style: styles14.header, children: [
32469
32684
  /* @__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" }) })
32685
+ /* @__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
32686
  ] }),
32472
32687
  /* @__PURE__ */ jsxs13(ScrollView4, { style: styles14.content, keyboardShouldPersistTaps: "handled", children: [
32473
32688
  quote ? /* @__PURE__ */ jsx18(Text8, { style: [styles14.quote, textStyle], selectable: true, children: quote }) : null,
32474
32689
  editing ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
32475
32690
  /* @__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
32691
  /* @__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)) })
32692
+ /* @__PURE__ */ jsx18(View14, { style: styles14.markupOptions, children: [
32693
+ ["highlight", t.annotationHighlight, IconHighlight],
32694
+ ["underline", t.annotationUnderline, IconUnderline],
32695
+ ["strikeout", t.annotationStrikeout, IconStrikeout],
32696
+ ["none", t.annotationIndicatorOnly, IconComment]
32697
+ ].map(([style, label, Icon]) => /* @__PURE__ */ jsxs13(
32698
+ Pressable9,
32699
+ {
32700
+ onPress: () => setMarkup(style),
32701
+ accessibilityRole: "button",
32702
+ accessibilityLabel: label,
32703
+ accessibilityState: { selected: markup === style },
32704
+ testID: `annotation-style-${style}`,
32705
+ style: [styles14.markupButton, { backgroundColor: dark ? "#242936" : "#f1f5f9", borderColor: markup === style ? accentColor : "transparent" }],
32706
+ children: [
32707
+ /* @__PURE__ */ jsx18(View14, { accessible: false, importantForAccessibility: "no-hide-descendants", children: /* @__PURE__ */ jsx18(Icon, { size: 22, color: markup === style ? accentColor : textStyle.color }) }),
32708
+ /* @__PURE__ */ jsx18(Text8, { style: [styles14.markupLabel, textStyle], children: style === "none" ? locale === "pt-BR" ? "Indicador" : "Indicator" : label })
32709
+ ]
32710
+ },
32711
+ style
32712
+ )) })
32478
32713
  ] }) : /* @__PURE__ */ jsx18(Text8, { style: [styles14.note, textStyle], selectable: true, children: getAnnotationNote2(annotation) || t.notePlaceholder })
32479
32714
  ] }),
32480
32715
  /* @__PURE__ */ jsxs13(View14, { style: styles14.actions, children: [
@@ -32497,11 +32732,11 @@ var AnnotationEditor = () => {
32497
32732
  ] })
32498
32733
  ] }) });
32499
32734
  };
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 } });
32735
+ 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
32736
  var AnnotationEditor_default = AnnotationEditor;
32502
32737
 
32503
32738
  // components/BottomBar.tsx
32504
- import { View as View15, Pressable as Pressable10, StyleSheet as StyleSheet15, useWindowDimensions as useWindowDimensions7 } from "react-native";
32739
+ import { View as View15, Text as Text9, Pressable as Pressable10, StyleSheet as StyleSheet15, useWindowDimensions as useWindowDimensions7 } from "react-native";
32505
32740
  import { useViewerStore as useViewerStore13 } from "@papyrus-sdk/core";
32506
32741
  import Animated5, { useAnimatedStyle as useAnimatedStyle2 } from "react-native-reanimated";
32507
32742
 
@@ -32555,15 +32790,24 @@ function resolveAnnotateButtonAction(input) {
32555
32790
  }
32556
32791
 
32557
32792
  // components/BottomBar.tsx
32558
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
32793
+ import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
32559
32794
  var BottomBar = ({
32560
32795
  documentType,
32561
32796
  onOpenInfo,
32562
32797
  onOpenSettings,
32563
- onOpenDestination
32798
+ onOpenDestination,
32799
+ onTurnPage,
32800
+ onNavigateToPage,
32801
+ onOpenPages
32564
32802
  }) => {
32565
32803
  const {
32566
32804
  activeMobileDestination,
32805
+ viewMode,
32806
+ epubReadingMode,
32807
+ epubLocation,
32808
+ comicLayoutMode,
32809
+ currentPage,
32810
+ pageCount,
32567
32811
  mobileDockVisible,
32568
32812
  setDocumentState,
32569
32813
  uiTheme,
@@ -32578,7 +32822,7 @@ var BottomBar = ({
32578
32822
  const supportsInkChrome = documentType === "pdf" && inkSession.supported;
32579
32823
  const drawing = supportsInkChrome && inkSession.active;
32580
32824
  const dockVisible = mobileChromeVisible && mobileDockVisible && !drawing;
32581
- const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome);
32825
+ const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome || documentType === "epub");
32582
32826
  const dockMotion = useAnimatedStyle2(() => {
32583
32827
  "worklet";
32584
32828
  return {
@@ -32600,6 +32844,15 @@ var BottomBar = ({
32600
32844
  activeMobileDestination,
32601
32845
  toolDockOpen
32602
32846
  });
32847
+ const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single");
32848
+ if (paginated) {
32849
+ layout.leftSlots.push(...layout.rightSlots.filter((slot) => slot.key === "search"));
32850
+ layout.rightSlots = [];
32851
+ }
32852
+ const turnPage = (direction) => {
32853
+ if (onTurnPage) onTurnPage(direction);
32854
+ else onNavigateToPage?.(currentPage + direction);
32855
+ };
32603
32856
  const slotMeta = {
32604
32857
  annotate: {
32605
32858
  label: t.tools,
@@ -32660,7 +32913,7 @@ var BottomBar = ({
32660
32913
  onPress: onOpenSettings
32661
32914
  }
32662
32915
  };
32663
- if (!dockVisible && !supportsInkChrome) return null;
32916
+ if (!dockVisible && !supportsInkChrome && documentType !== "epub") return null;
32664
32917
  return /* @__PURE__ */ jsx19(
32665
32918
  Animated5.View,
32666
32919
  {
@@ -32725,7 +32978,11 @@ var BottomBar = ({
32725
32978
  isDark && styles15.islandDark
32726
32979
  ],
32727
32980
  testID: "papyrus-floating-bottom-dock",
32728
- children: layout.rightSlots.map((slot) => {
32981
+ children: paginated ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
32982
+ /* @__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) }) }),
32983
+ /* @__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}` }) }),
32984
+ /* @__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) }) })
32985
+ ] }) : layout.rightSlots.map((slot) => {
32729
32986
  const meta = slotMeta[slot.key];
32730
32987
  const Icon = meta.icon;
32731
32988
  return /* @__PURE__ */ jsx19(
@@ -32788,8 +33045,9 @@ var styles15 = StyleSheet15.create({
32788
33045
  island: {
32789
33046
  flexDirection: "row",
32790
33047
  alignItems: "center",
32791
- paddingVertical: 8,
32792
- paddingHorizontal: 10,
33048
+ height: MOBILE_CHROME_METRICS.bottomBarVisualHeight,
33049
+ paddingVertical: 0,
33050
+ paddingHorizontal: 6,
32793
33051
  backgroundColor: "rgba(255,255,255,0.9)",
32794
33052
  borderWidth: 1,
32795
33053
  borderColor: "rgba(255,255,255,0.72)",
@@ -32815,6 +33073,8 @@ var styles15 = StyleSheet15.create({
32815
33073
  borderColor: "rgba(71,85,105,0.48)"
32816
33074
  },
32817
33075
  iconOnlyItem: {
33076
+ minWidth: 44,
33077
+ height: 44,
32818
33078
  alignItems: "center",
32819
33079
  justifyContent: "center",
32820
33080
  paddingHorizontal: MOBILE_CHROME_METRICS.bottomBarItemPaddingHorizontal,
@@ -32845,9 +33105,9 @@ var BottomBar_default = BottomBar;
32845
33105
  // components/SettingsSheet.tsx
32846
33106
  import {
32847
33107
  View as View16,
32848
- Text as Text9,
33108
+ Text as Text10,
32849
33109
  Pressable as Pressable11,
32850
- Platform as Platform8,
33110
+ Platform as Platform9,
32851
33111
  StyleSheet as StyleSheet16,
32852
33112
  useWindowDimensions as useWindowDimensions8
32853
33113
  } from "react-native";
@@ -32898,10 +33158,12 @@ var SettingsSheet = ({
32898
33158
  engine,
32899
33159
  visible,
32900
33160
  onClose,
32901
- documentType = "pdf"
33161
+ documentType = "pdf",
33162
+ onOpenInfo
32902
33163
  }) => {
32903
33164
  const {
32904
33165
  viewMode,
33166
+ epubReadingMode,
32905
33167
  uiTheme,
32906
33168
  zoom,
32907
33169
  setDocumentState,
@@ -32913,12 +33175,16 @@ var SettingsSheet = ({
32913
33175
  comicReadingDirection
32914
33176
  } = useViewerStore14();
32915
33177
  const isDark = uiTheme === "dark";
32916
- const isPaged = viewMode === "single";
33178
+ const isPaged = documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single";
32917
33179
  const isDouble = viewMode === "double";
32918
33180
  const t = getStrings(locale);
32919
33181
  const { height: windowHeight } = useWindowDimensions8();
32920
33182
  const sheetMaxHeight = getSettingsSheetMaxHeight(windowHeight);
32921
33183
  const handleTransition = (mode) => {
33184
+ if (documentType === "epub") {
33185
+ setDocumentState({ epubReadingMode: mode === "paged" ? "paged" : "chapter-scroll" });
33186
+ return;
33187
+ }
32922
33188
  if (mode === "paged") {
32923
33189
  setDocumentState({ viewMode: "single" });
32924
33190
  return;
@@ -32963,22 +33229,23 @@ var SettingsSheet = ({
32963
33229
  contentContainerStyle: styles16.sheetContent,
32964
33230
  showsVerticalScrollIndicator: false,
32965
33231
  children: [
33232
+ 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
33233
  (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" }),
33234
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: locale === "pt-BR" ? "Tamanho da fonte" : "Font size" }),
32968
33235
  /* @__PURE__ */ jsxs15(View16, { style: { flexDirection: "row", alignItems: "center", gap: 12 }, children: [
32969
33236
  [-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
33237
  const next = Math.max(0.7, Math.min(2, zoom + delta));
32971
33238
  if (documentType === "epub") engine.setZoom(next);
32972
33239
  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: [
33240
+ }, 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)),
33241
+ /* @__PURE__ */ jsxs15(Text10, { style: { color: isDark ? "#fff" : "#111" }, children: [
32975
33242
  Math.round(zoom * 100),
32976
33243
  "%"
32977
33244
  ] })
32978
33245
  ] })
32979
33246
  ] }),
32980
33247
  documentType === "comic" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
32981
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicMode }),
33248
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicMode }),
32982
33249
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["single", "continuous"].map((mode) => {
32983
33250
  const active = comicLayoutMode === mode;
32984
33251
  return /* @__PURE__ */ jsx20(
@@ -32986,12 +33253,12 @@ var SettingsSheet = ({
32986
33253
  {
32987
33254
  onPress: () => setDocumentState({ comicLayoutMode: mode }),
32988
33255
  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 })
33256
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "single" ? t.comicSingle : t.comicContinuous })
32990
33257
  },
32991
33258
  mode
32992
33259
  );
32993
33260
  }) }),
32994
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicFit }),
33261
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicFit }),
32995
33262
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["width", "page"].map((mode) => {
32996
33263
  const active = comicFitMode === mode;
32997
33264
  return /* @__PURE__ */ jsx20(
@@ -32999,12 +33266,12 @@ var SettingsSheet = ({
32999
33266
  {
33000
33267
  onPress: () => setDocumentState({ comicFitMode: mode }),
33001
33268
  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 })
33269
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: mode === "width" ? t.comicFitWidth : t.comicFitPage })
33003
33270
  },
33004
33271
  mode
33005
33272
  );
33006
33273
  }) }),
33007
- /* @__PURE__ */ jsx20(Text9, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicDirection }),
33274
+ /* @__PURE__ */ jsx20(Text10, { style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark], children: t.comicDirection }),
33008
33275
  /* @__PURE__ */ jsx20(View16, { style: styles16.optionRow, children: ["ltr", "rtl"].map((direction) => {
33009
33276
  const active = comicReadingDirection === direction;
33010
33277
  return /* @__PURE__ */ jsx20(
@@ -33012,7 +33279,7 @@ var SettingsSheet = ({
33012
33279
  {
33013
33280
  onPress: () => setDocumentState({ comicReadingDirection: direction }),
33014
33281
  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 })
33282
+ children: /* @__PURE__ */ jsx20(Text10, { style: [styles16.optionText, isDark && styles16.optionTextDark, active && styles16.optionTextActive], children: direction === "ltr" ? t.comicLtr : t.comicRtl })
33016
33283
  },
33017
33284
  direction
33018
33285
  );
@@ -33020,7 +33287,7 @@ var SettingsSheet = ({
33020
33287
  ] }),
33021
33288
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33022
33289
  /* @__PURE__ */ jsx20(
33023
- Text9,
33290
+ Text10,
33024
33291
  {
33025
33292
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33026
33293
  children: t.appearance
@@ -33038,7 +33305,7 @@ var SettingsSheet = ({
33038
33305
  uiTheme === "light" && { backgroundColor: accentColor }
33039
33306
  ],
33040
33307
  children: /* @__PURE__ */ jsx20(
33041
- Text9,
33308
+ Text10,
33042
33309
  {
33043
33310
  style: [
33044
33311
  styles16.optionText,
@@ -33061,7 +33328,7 @@ var SettingsSheet = ({
33061
33328
  uiTheme === "dark" && { backgroundColor: accentColor }
33062
33329
  ],
33063
33330
  children: /* @__PURE__ */ jsx20(
33064
- Text9,
33331
+ Text10,
33065
33332
  {
33066
33333
  style: [
33067
33334
  styles16.optionText,
@@ -33077,7 +33344,7 @@ var SettingsSheet = ({
33077
33344
  ] }),
33078
33345
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33079
33346
  /* @__PURE__ */ jsx20(
33080
- Text9,
33347
+ Text10,
33081
33348
  {
33082
33349
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33083
33350
  children: t.pageTheme
@@ -33098,7 +33365,7 @@ var SettingsSheet = ({
33098
33365
  children: [
33099
33366
  /* @__PURE__ */ jsx20(ThemeSwatch, { value: option.value }),
33100
33367
  /* @__PURE__ */ jsx20(
33101
- Text9,
33368
+ Text10,
33102
33369
  {
33103
33370
  style: [
33104
33371
  styles16.themeOptionLabel,
@@ -33116,7 +33383,7 @@ var SettingsSheet = ({
33116
33383
  ] }),
33117
33384
  documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33118
33385
  /* @__PURE__ */ jsx20(
33119
- Text9,
33386
+ Text10,
33120
33387
  {
33121
33388
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33122
33389
  children: t.pageTransition
@@ -33134,14 +33401,14 @@ var SettingsSheet = ({
33134
33401
  (!isPaged || isDouble) && { backgroundColor: accentColor }
33135
33402
  ],
33136
33403
  children: /* @__PURE__ */ jsx20(
33137
- Text9,
33404
+ Text10,
33138
33405
  {
33139
33406
  style: [
33140
33407
  styles16.optionText,
33141
33408
  isDark && styles16.optionTextDark,
33142
33409
  (!isPaged || isDouble) && styles16.optionTextActive
33143
33410
  ],
33144
- children: t.continuous
33411
+ children: documentType === "epub" && locale === "pt-BR" ? "Rolagem por cap\xEDtulo" : t.continuous
33145
33412
  }
33146
33413
  )
33147
33414
  }
@@ -33157,7 +33424,7 @@ var SettingsSheet = ({
33157
33424
  isPaged && { backgroundColor: accentColor }
33158
33425
  ],
33159
33426
  children: /* @__PURE__ */ jsx20(
33160
- Text9,
33427
+ Text10,
33161
33428
  {
33162
33429
  style: [
33163
33430
  styles16.optionText,
@@ -33171,9 +33438,9 @@ var SettingsSheet = ({
33171
33438
  )
33172
33439
  ] })
33173
33440
  ] }),
33174
- documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33441
+ documentType === "pdf" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33175
33442
  /* @__PURE__ */ jsx20(
33176
- Text9,
33443
+ Text10,
33177
33444
  {
33178
33445
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33179
33446
  children: t.layout
@@ -33191,7 +33458,7 @@ var SettingsSheet = ({
33191
33458
  !isDouble && { backgroundColor: accentColor }
33192
33459
  ],
33193
33460
  children: /* @__PURE__ */ jsx20(
33194
- Text9,
33461
+ Text10,
33195
33462
  {
33196
33463
  style: [
33197
33464
  styles16.optionText,
@@ -33214,7 +33481,7 @@ var SettingsSheet = ({
33214
33481
  isDouble && { backgroundColor: accentColor }
33215
33482
  ],
33216
33483
  children: /* @__PURE__ */ jsx20(
33217
- Text9,
33484
+ Text10,
33218
33485
  {
33219
33486
  style: [
33220
33487
  styles16.optionText,
@@ -33230,7 +33497,7 @@ var SettingsSheet = ({
33230
33497
  ] }),
33231
33498
  documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33232
33499
  /* @__PURE__ */ jsx20(
33233
- Text9,
33500
+ Text10,
33234
33501
  {
33235
33502
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33236
33503
  children: t.rotate
@@ -33243,7 +33510,7 @@ var SettingsSheet = ({
33243
33510
  onPress: () => handleRotate("counterclockwise"),
33244
33511
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33245
33512
  children: /* @__PURE__ */ jsx20(
33246
- Text9,
33513
+ Text10,
33247
33514
  {
33248
33515
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33249
33516
  children: t.counterclockwise
@@ -33251,13 +33518,13 @@ var SettingsSheet = ({
33251
33518
  )
33252
33519
  }
33253
33520
  ),
33254
- Platform8.OS === "ios" && /* @__PURE__ */ jsx20(
33521
+ Platform9.OS === "ios" && /* @__PURE__ */ jsx20(
33255
33522
  Pressable11,
33256
33523
  {
33257
33524
  onPress: handleResetRotation,
33258
33525
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33259
33526
  children: /* @__PURE__ */ jsx20(
33260
- Text9,
33527
+ Text10,
33261
33528
  {
33262
33529
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33263
33530
  children: t.rotationOriginal
@@ -33271,7 +33538,7 @@ var SettingsSheet = ({
33271
33538
  onPress: () => handleRotate("clockwise"),
33272
33539
  style: [styles16.optionButton, isDark && styles16.optionButtonDark],
33273
33540
  children: /* @__PURE__ */ jsx20(
33274
- Text9,
33541
+ Text10,
33275
33542
  {
33276
33543
  style: [styles16.optionText, isDark && styles16.optionTextDark],
33277
33544
  children: t.clockwise
@@ -33283,7 +33550,7 @@ var SettingsSheet = ({
33283
33550
  ] }),
33284
33551
  documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33285
33552
  /* @__PURE__ */ jsx20(
33286
- Text9,
33553
+ Text10,
33287
33554
  {
33288
33555
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33289
33556
  children: t.zoom
@@ -33298,7 +33565,7 @@ var SettingsSheet = ({
33298
33565
  children: /* @__PURE__ */ jsx20(IconZoomOut, { size: 16, color: isDark ? "#e5e7eb" : "#111827" })
33299
33566
  }
33300
33567
  ),
33301
- /* @__PURE__ */ jsx20(View16, { style: styles16.zoomValue, children: /* @__PURE__ */ jsxs15(Text9, { style: [styles16.zoomText, isDark && styles16.zoomTextDark], children: [
33568
+ /* @__PURE__ */ jsx20(View16, { style: styles16.zoomValue, children: /* @__PURE__ */ jsxs15(Text10, { style: [styles16.zoomText, isDark && styles16.zoomTextDark], children: [
33302
33569
  Math.round(zoom * 100),
33303
33570
  "%"
33304
33571
  ] }) }),
@@ -33314,7 +33581,7 @@ var SettingsSheet = ({
33314
33581
  ] }),
33315
33582
  /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33316
33583
  /* @__PURE__ */ jsx20(
33317
- Text9,
33584
+ Text10,
33318
33585
  {
33319
33586
  style: [styles16.sectionTitle, isDark && styles16.sectionTitleDark],
33320
33587
  children: t.language
@@ -33332,7 +33599,7 @@ var SettingsSheet = ({
33332
33599
  locale === "en" && { backgroundColor: accentColor }
33333
33600
  ],
33334
33601
  children: /* @__PURE__ */ jsx20(
33335
- Text9,
33602
+ Text10,
33336
33603
  {
33337
33604
  style: [
33338
33605
  styles16.optionText,
@@ -33355,7 +33622,7 @@ var SettingsSheet = ({
33355
33622
  locale === "pt-BR" && { backgroundColor: accentColor }
33356
33623
  ],
33357
33624
  children: /* @__PURE__ */ jsx20(
33358
- Text9,
33625
+ Text10,
33359
33626
  {
33360
33627
  style: [
33361
33628
  styles16.optionText,
@@ -33512,7 +33779,7 @@ import { useEffect as useEffect14, useMemo as useMemo8, useRef as useRef10, useS
33512
33779
  import {
33513
33780
  ActivityIndicator,
33514
33781
  StyleSheet as StyleSheet17,
33515
- Text as Text10,
33782
+ Text as Text11,
33516
33783
  UIManager as UIManager2,
33517
33784
  View as View17,
33518
33785
  findNodeHandle as findNodeHandle3
@@ -33635,12 +33902,12 @@ var CoverPreview = ({
33635
33902
  }
33636
33903
  };
33637
33904
  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" }) }) });
33905
+ 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
33906
  }
33640
33907
  return /* @__PURE__ */ jsxs16(View17, { style: [styles17.container, style], onLayout: handleLayout, children: [
33641
33908
  /* @__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
33909
  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" }) })
33910
+ error && /* @__PURE__ */ jsx21(View17, { pointerEvents: "none", style: styles17.errorOverlay, children: /* @__PURE__ */ jsx21(Text11, { style: styles17.errorText, children: "Preview unavailable" }) })
33644
33911
  ] });
33645
33912
  };
33646
33913
  var styles17 = StyleSheet17.create({
@@ -33695,7 +33962,7 @@ import { Keyboard as Keyboard2, View as View23, StyleSheet as StyleSheet24 } fro
33695
33962
  import { useViewerStore as useViewerStore21 } from "@papyrus-sdk/core";
33696
33963
 
33697
33964
  // components/DocumentActionsSheet.tsx
33698
- import { StyleSheet as StyleSheet18, Text as Text11, View as View18 } from "react-native";
33965
+ import { StyleSheet as StyleSheet18, Text as Text12, View as View18 } from "react-native";
33699
33966
  import { useViewerStore as useViewerStore15 } from "@papyrus-sdk/core";
33700
33967
  import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
33701
33968
  function DocumentActionsSheet({
@@ -33732,7 +33999,7 @@ function DocumentActionsSheet({
33732
33999
  borderColor: palette.divider
33733
34000
  }
33734
34001
  ],
33735
- children: /* @__PURE__ */ jsx22(Text11, { style: [styles18.actionText, { color: palette.text }], children: "Share" })
34002
+ children: /* @__PURE__ */ jsx22(Text12, { style: [styles18.actionText, { color: palette.text }], children: "Share" })
33736
34003
  }
33737
34004
  ),
33738
34005
  /* @__PURE__ */ jsx22(
@@ -33745,7 +34012,7 @@ function DocumentActionsSheet({
33745
34012
  borderColor: palette.divider
33746
34013
  }
33747
34014
  ],
33748
- children: /* @__PURE__ */ jsx22(Text11, { style: [styles18.actionText, { color: palette.text }], children: "Export" })
34015
+ children: /* @__PURE__ */ jsx22(Text12, { style: [styles18.actionText, { color: palette.text }], children: "Export" })
33749
34016
  }
33750
34017
  )
33751
34018
  ] })
@@ -33770,7 +34037,7 @@ var styles18 = StyleSheet18.create({
33770
34037
  });
33771
34038
 
33772
34039
  // components/InfoSheet.tsx
33773
- import { StyleSheet as StyleSheet19, Text as Text12, View as View19 } from "react-native";
34040
+ import { StyleSheet as StyleSheet19, Text as Text13, View as View19 } from "react-native";
33774
34041
  import { useViewerStore as useViewerStore16 } from "@papyrus-sdk/core";
33775
34042
 
33776
34043
  // components/infoSheetModel.ts
@@ -33924,15 +34191,15 @@ function InfoSheet({
33924
34191
  contentContainerStyle: styles19.contentInner,
33925
34192
  showsVerticalScrollIndicator: false,
33926
34193
  children: [
33927
- /* @__PURE__ */ jsx23(Text12, { style: [styles19.sectionTitle, { color: palette.mutedText }], children: isPortuguese ? "Resumo do documento" : "Document summary" }),
34194
+ /* @__PURE__ */ jsx23(Text13, { style: [styles19.sectionTitle, { color: palette.mutedText }], children: isPortuguese ? "Resumo do documento" : "Document summary" }),
33928
34195
  /* @__PURE__ */ jsx23(View19, { style: [styles19.rows, { borderTopColor: palette.divider }], children: rows.map((row) => /* @__PURE__ */ jsxs18(
33929
34196
  View19,
33930
34197
  {
33931
34198
  style: [styles19.row, { borderBottomColor: palette.divider }],
33932
34199
  children: [
33933
- /* @__PURE__ */ jsx23(Text12, { style: [styles19.label, { color: palette.mutedText }], children: row.label }),
34200
+ /* @__PURE__ */ jsx23(Text13, { style: [styles19.label, { color: palette.mutedText }], children: row.label }),
33934
34201
  /* @__PURE__ */ jsx23(
33935
- Text12,
34202
+ Text13,
33936
34203
  {
33937
34204
  style: [styles19.value, { color: palette.text }],
33938
34205
  selectable: true,
@@ -33995,7 +34262,7 @@ var styles19 = StyleSheet19.create({
33995
34262
  });
33996
34263
 
33997
34264
  // components/OverflowSheet.tsx
33998
- import { Pressable as Pressable12, StyleSheet as StyleSheet20, Text as Text13, View as View20 } from "react-native";
34265
+ import { Pressable as Pressable12, StyleSheet as StyleSheet20, Text as Text14, View as View20 } from "react-native";
33999
34266
  import { useViewerStore as useViewerStore17 } from "@papyrus-sdk/core";
34000
34267
  import { jsx as jsx24 } from "react/jsx-runtime";
34001
34268
  var actionLabels = [{ key: "actions", label: "Document actions" }];
@@ -34035,7 +34302,7 @@ function OverflowSheet({
34035
34302
  ],
34036
34303
  accessibilityRole: "button",
34037
34304
  accessibilityLabel: action.label,
34038
- children: /* @__PURE__ */ jsx24(Text13, { style: [styles20.actionText, { color: palette.text }], children: action.label })
34305
+ children: /* @__PURE__ */ jsx24(Text14, { style: [styles20.actionText, { color: palette.text }], children: action.label })
34039
34306
  },
34040
34307
  action.key
34041
34308
  )) })
@@ -34060,10 +34327,11 @@ import {
34060
34327
  PanResponder as PanResponder2,
34061
34328
  Pressable as Pressable13,
34062
34329
  StyleSheet as StyleSheet21,
34063
- Text as Text14,
34330
+ Text as Text15,
34064
34331
  View as View21,
34065
34332
  useWindowDimensions as useWindowDimensions9
34066
34333
  } from "react-native";
34334
+ import Reanimated, { useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
34067
34335
  import { useViewerStore as useViewerStore18 } from "@papyrus-sdk/core";
34068
34336
 
34069
34337
  // components/progressPillMode.ts
@@ -34083,9 +34351,11 @@ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
34083
34351
  var clampPercent = (value) => Math.max(0, Math.min(100, Math.round(value)));
34084
34352
  function ProgressPill({
34085
34353
  documentType,
34354
+ navigationInDock = false,
34086
34355
  onPress,
34087
34356
  onOpenPageJump,
34088
34357
  onNavigateToPage,
34358
+ onTurnPage,
34089
34359
  onScrubbingChange
34090
34360
  }) {
34091
34361
  const {
@@ -34095,12 +34365,20 @@ function ProgressPill({
34095
34365
  textLength,
34096
34366
  comicLayoutMode,
34097
34367
  viewMode,
34368
+ epubReadingMode,
34369
+ epubLocation,
34098
34370
  locale,
34099
34371
  uiTheme,
34100
34372
  accentColor,
34101
34373
  mobileChromeVisible,
34102
34374
  mobileProgressPillVisible
34103
34375
  } = useViewerStore18();
34376
+ const chromeVisible = mobileChromeVisible && mobileProgressPillVisible;
34377
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
34378
+ const chromeMotion = useAnimatedStyle3(() => {
34379
+ "worklet";
34380
+ return { opacity: chromeProgress.value };
34381
+ });
34104
34382
  const t = getStrings(locale);
34105
34383
  const isDark = uiTheme === "dark";
34106
34384
  const offsets = resolveMobileChromeOffsets(usePapyrusSafeAreaInsets());
@@ -34145,10 +34423,10 @@ function ProgressPill({
34145
34423
  return `${displayedPage}/${pageCount || 0}`;
34146
34424
  }
34147
34425
  if (documentType === "epub") {
34148
- return `Cap. ${displayedPage} \xB7 ${percent}%`;
34426
+ return `Cap. ${displayedPage} \xB7 ${scrubPreviewPage === null && epubLocation ? clampPercent(epubLocation.progress * 100) : percent}%`;
34149
34427
  }
34150
34428
  return `${percent}%`;
34151
- }, [displayedPage, documentType, pageCount]);
34429
+ }, [displayedPage, documentType, pageCount, epubLocation, scrubPreviewPage]);
34152
34430
  const thumbTop = resolvePageScrubberThumbTop({
34153
34431
  currentPage,
34154
34432
  trackHeight,
@@ -34190,7 +34468,7 @@ function ProgressPill({
34190
34468
  },
34191
34469
  []
34192
34470
  );
34193
- if (!shouldRenderPageScrubber({
34471
+ if (!(documentType === "epub" && mobileProgressPillVisible) && !shouldRenderPageScrubber({
34194
34472
  mobileChromeVisible,
34195
34473
  mobileProgressPillVisible,
34196
34474
  isScrubbing: isScrubbingRef.current
@@ -34212,7 +34490,7 @@ function ProgressPill({
34212
34490
  onPress: () => onPressRef.current(),
34213
34491
  style: [styles21.singlePill, isDark && styles21.pillDark],
34214
34492
  testID: "papyrus-progress-text",
34215
- children: /* @__PURE__ */ jsxs19(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: [
34493
+ children: /* @__PURE__ */ jsxs19(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: [
34216
34494
  progress,
34217
34495
  "%"
34218
34496
  ] })
@@ -34221,16 +34499,17 @@ function ProgressPill({
34221
34499
  }
34222
34500
  );
34223
34501
  }
34224
- const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : viewMode;
34502
+ const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : documentType === "epub" ? epubReadingMode === "paged" ? "single" : "continuous" : viewMode;
34225
34503
  const pillMode = resolveProgressPillMode(progressViewMode, currentPage, pageCount);
34504
+ if (pillMode.kind === "navigation" && navigationInDock) return null;
34226
34505
  if (pillMode.kind === "navigation") {
34227
- const previousDisabled = pillMode.previousPage === null || !onNavigateToPage;
34228
- const nextDisabled = pillMode.nextPage === null || !onNavigateToPage;
34506
+ const previousDisabled = !onTurnPage && (pillMode.previousPage === null || !onNavigateToPage);
34507
+ const nextDisabled = !onTurnPage && (pillMode.nextPage === null || !onNavigateToPage);
34229
34508
  return /* @__PURE__ */ jsx25(
34230
34509
  View21,
34231
34510
  {
34232
34511
  pointerEvents: "box-none",
34233
- style: [styles21.frame, styles21.singleFrame, { top: offsets.progress, right: offsets.right }],
34512
+ style: [{ position: "absolute", zIndex: 18, bottom: offsets.bottom + MOBILE_CHROME_METRICS.bottomBarVisualHeight + 12, left: offsets.left, right: offsets.right, alignItems: "center" }],
34234
34513
  children: /* @__PURE__ */ jsxs19(View21, { style: [styles21.singlePill, isDark && styles21.pillDark], children: [
34235
34514
  /* @__PURE__ */ jsx25(
34236
34515
  Pressable13,
@@ -34239,10 +34518,10 @@ function ProgressPill({
34239
34518
  accessibilityLabel: t.previousPage,
34240
34519
  accessibilityState: { disabled: previousDisabled },
34241
34520
  disabled: previousDisabled,
34242
- onPress: () => pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34521
+ onPress: () => onTurnPage ? onTurnPage(-1) : pillMode.previousPage !== null && onNavigateToPageRef.current?.(pillMode.previousPage),
34243
34522
  style: styles21.pageArrowHit,
34244
34523
  testID: "papyrus-progress-page-previous",
34245
- children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.pageArrow, isDark && styles21.labelDark, previousDisabled && styles21.pageArrowDisabled], children: "\u2039" })
34524
+ children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.pageArrow, isDark && styles21.labelDark, previousDisabled && styles21.pageArrowDisabled], children: "\u2039" })
34246
34525
  }
34247
34526
  ),
34248
34527
  /* @__PURE__ */ jsx25(
@@ -34253,7 +34532,7 @@ function ProgressPill({
34253
34532
  onPress: () => onPressRef.current(),
34254
34533
  style: styles21.singlePageCenter,
34255
34534
  testID: "papyrus-progress-page-grid",
34256
- children: /* @__PURE__ */ jsxs19(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: [
34535
+ children: /* @__PURE__ */ jsxs19(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: [
34257
34536
  currentPage,
34258
34537
  "/",
34259
34538
  pageCount || 0
@@ -34267,10 +34546,10 @@ function ProgressPill({
34267
34546
  accessibilityLabel: t.nextPage,
34268
34547
  accessibilityState: { disabled: nextDisabled },
34269
34548
  disabled: nextDisabled,
34270
- onPress: () => pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34549
+ onPress: () => onTurnPage ? onTurnPage(1) : pillMode.nextPage !== null && onNavigateToPageRef.current?.(pillMode.nextPage),
34271
34550
  style: styles21.pageArrowHit,
34272
34551
  testID: "papyrus-progress-page-next",
34273
- children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.pageArrow, isDark && styles21.labelDark, nextDisabled && styles21.pageArrowDisabled], children: "\u203A" })
34552
+ children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.pageArrow, isDark && styles21.labelDark, nextDisabled && styles21.pageArrowDisabled], children: "\u203A" })
34274
34553
  }
34275
34554
  )
34276
34555
  ] })
@@ -34411,11 +34690,14 @@ function ProgressPill({
34411
34690
  }
34412
34691
  const responderPanHandlers = scrubberResponderRef.current?.panHandlers ?? {};
34413
34692
  return /* @__PURE__ */ jsx25(
34414
- View21,
34693
+ Reanimated.View,
34415
34694
  {
34416
- pointerEvents: "box-none",
34695
+ pointerEvents: chromeVisible ? "box-none" : "none",
34696
+ accessibilityElementsHidden: !chromeVisible,
34697
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
34417
34698
  style: [
34418
34699
  styles21.frame,
34700
+ chromeMotion,
34419
34701
  resolvePageScrubberOverlayStyle(),
34420
34702
  {
34421
34703
  top: offsets.progress,
@@ -34466,7 +34748,7 @@ function ProgressPill({
34466
34748
  ...responderPanHandlers,
34467
34749
  testID: "papyrus-progress-pill",
34468
34750
  children: [
34469
- /* @__PURE__ */ jsx25(View21, { style: styles21.labelHit, children: /* @__PURE__ */ jsx25(Text14, { style: [styles21.label, isDark && styles21.labelDark], children: label }) }),
34751
+ /* @__PURE__ */ jsx25(View21, { style: styles21.labelHit, children: /* @__PURE__ */ jsx25(Text15, { style: [styles21.label, isDark && styles21.labelDark], children: label }) }),
34470
34752
  /* @__PURE__ */ jsx25(View21, { style: styles21.iconHit, children: /* @__PURE__ */ jsx25(
34471
34753
  IconPageNav,
34472
34754
  {
@@ -34597,7 +34879,7 @@ import {
34597
34879
  Keyboard,
34598
34880
  Pressable as Pressable14,
34599
34881
  StyleSheet as StyleSheet22,
34600
- Text as Text15,
34882
+ Text as Text16,
34601
34883
  TextInput as TextInput3,
34602
34884
  View as View22,
34603
34885
  useWindowDimensions as useWindowDimensions10
@@ -34730,7 +35012,7 @@ function SearchOverlay({
34730
35012
  onPress: handleClose,
34731
35013
  style: [styles22.closeButton, isDark && styles22.closeButtonDark],
34732
35014
  accessibilityLabel: "Close search",
34733
- children: /* @__PURE__ */ jsx26(Text15, { style: [styles22.closeText, isDark && styles22.closeTextDark], children: t.cancel })
35015
+ children: /* @__PURE__ */ jsx26(Text16, { style: [styles22.closeText, isDark && styles22.closeTextDark], children: t.cancel })
34734
35016
  }
34735
35017
  )
34736
35018
  ] }),
@@ -34749,7 +35031,7 @@ function SearchOverlay({
34749
35031
  children: /* @__PURE__ */ jsx26(IconChevronLeft, { size: 16, color: isDark ? "#e5e7eb" : "#111827" })
34750
35032
  }
34751
35033
  ),
34752
- /* @__PURE__ */ jsx26(Text15, { style: [styles22.metaText, isDark && styles22.metaTextDark], children: isSearching ? t.searching : `${currentCount}/${results.length} ${targetLabel}` }),
35034
+ /* @__PURE__ */ jsx26(Text16, { style: [styles22.metaText, isDark && styles22.metaTextDark], children: isSearching ? t.searching : `${currentCount}/${results.length} ${targetLabel}` }),
34753
35035
  /* @__PURE__ */ jsx26(
34754
35036
  Pressable14,
34755
35037
  {
@@ -34773,7 +35055,7 @@ function SearchOverlay({
34773
35055
  style: [styles22.primaryAction, { backgroundColor: accentColor }],
34774
35056
  accessibilityLabel: "Run search",
34775
35057
  testID: "papyrus-search-run",
34776
- children: /* @__PURE__ */ jsx26(Text15, { style: styles22.primaryActionText, children: t.searchGo })
35058
+ children: /* @__PURE__ */ jsx26(Text16, { style: styles22.primaryActionText, children: t.searchGo })
34777
35059
  }
34778
35060
  ),
34779
35061
  /* @__PURE__ */ jsx26(
@@ -34788,7 +35070,7 @@ function SearchOverlay({
34788
35070
  ],
34789
35071
  accessibilityLabel: "Open all results",
34790
35072
  children: /* @__PURE__ */ jsx26(
34791
- Text15,
35073
+ Text16,
34792
35074
  {
34793
35075
  style: [
34794
35076
  styles22.secondaryActionText,
@@ -34947,7 +35229,7 @@ var styles22 = StyleSheet22.create({
34947
35229
  });
34948
35230
 
34949
35231
  // components/SearchResultsSheet.tsx
34950
- import { Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text16 } from "react-native";
35232
+ import { Pressable as Pressable15, StyleSheet as StyleSheet23, Text as Text17 } from "react-native";
34951
35233
  import { useViewerStore as useViewerStore20 } from "@papyrus-sdk/core";
34952
35234
  import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
34953
35235
  function SearchResultsSheet({
@@ -34995,12 +35277,12 @@ function SearchResultsSheet({
34995
35277
  borderTopColor: palette.divider
34996
35278
  },
34997
35279
  children: [
34998
- /* @__PURE__ */ jsxs21(Text16, { style: [styles23.meta, { color: palette.mutedText }], children: [
35280
+ /* @__PURE__ */ jsxs21(Text17, { style: [styles23.meta, { color: palette.mutedText }], children: [
34999
35281
  results.length,
35000
35282
  " ",
35001
35283
  t.results
35002
35284
  ] }),
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) => {
35285
+ /* @__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
35286
  const isActive = index === activeSearchIndex;
35005
35287
  const isTextResult = "kind" in result && result.kind === "text";
35006
35288
  return /* @__PURE__ */ jsxs21(
@@ -35030,8 +35312,8 @@ function SearchResultsSheet({
35030
35312
  }
35031
35313
  ],
35032
35314
  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 })
35315
+ /* @__PURE__ */ jsx27(Text17, { style: [styles23.resultLabel, { color: accentColor }], children: isTextResult ? getTextResultLabel(result.location.start) : getResultLabel(result.pageIndex) }),
35316
+ /* @__PURE__ */ jsx27(Text17, { style: [styles23.resultText, { color: palette.text }], children: result.text })
35035
35317
  ]
35036
35318
  },
35037
35319
  isTextResult ? `text-${result.location.start}-${index}` : `page-${result.pageIndex}-${index}`
@@ -35152,15 +35434,10 @@ function ReadingShell({
35152
35434
  /* @__PURE__ */ jsx28(
35153
35435
  Topbar_default,
35154
35436
  {
35437
+ documentType,
35155
35438
  engine,
35156
35439
  title,
35157
- onOpenOverflow: () => {
35158
- closeMobileDestination();
35159
- setInfoOpen(false);
35160
- setActionsOpen(false);
35161
- setSettingsOpen(false);
35162
- setOverflowOpen(true);
35163
- },
35440
+ onOpenSettings: () => openDestination("display"),
35164
35441
  onOpenPageJump: () => setPageJumpOpen(true),
35165
35442
  showPageNavigationControls: false
35166
35443
  }
@@ -35168,6 +35445,7 @@ function ReadingShell({
35168
35445
  /* @__PURE__ */ jsx28(View23, { style: styles24.viewerStage, children: /* @__PURE__ */ jsx28(
35169
35446
  Viewer_default,
35170
35447
  {
35448
+ documentType,
35171
35449
  engine,
35172
35450
  ...viewerProps,
35173
35451
  pageScrubActive
@@ -35176,7 +35454,13 @@ function ReadingShell({
35176
35454
  /* @__PURE__ */ jsx28(
35177
35455
  ProgressPill,
35178
35456
  {
35457
+ navigationInDock: true,
35179
35458
  documentType,
35459
+ onTurnPage: documentType === "epub" ? (direction) => {
35460
+ const paginatedEngine = engine;
35461
+ void paginatedEngine.turnEpubPage?.(direction).catch(() => {
35462
+ });
35463
+ } : void 0,
35180
35464
  onNavigateToPage: navigateToPage,
35181
35465
  onPress: () => openDestination(
35182
35466
  documentType === "pdf" ? "pages" : documentType === "epub" ? "contents" : "progress"
@@ -35188,6 +35472,12 @@ function ReadingShell({
35188
35472
  /* @__PURE__ */ jsx28(
35189
35473
  BottomBar_default,
35190
35474
  {
35475
+ onNavigateToPage: navigateToPage,
35476
+ onOpenPages: () => setPageJumpOpen(true),
35477
+ onTurnPage: documentType === "epub" ? (direction) => {
35478
+ const paginatedEngine = engine;
35479
+ void paginatedEngine.turnEpubPage?.(direction).catch((error) => console.warn("[Papyrus] page navigation failed", error));
35480
+ } : void 0,
35191
35481
  documentType,
35192
35482
  onOpenDestination: openDestination,
35193
35483
  onOpenInfo: () => openDestination("info"),
@@ -35267,6 +35557,7 @@ function ReadingShell({
35267
35557
  /* @__PURE__ */ jsx28(
35268
35558
  SettingsSheet_default,
35269
35559
  {
35560
+ onOpenInfo: () => openDestination("info"),
35270
35561
  engine,
35271
35562
  documentType,
35272
35563
  visible: settingsOpen,
@@ -35279,6 +35570,7 @@ function ReadingShell({
35279
35570
  /* @__PURE__ */ jsx28(
35280
35571
  PageJumpModal,
35281
35572
  {
35573
+ documentType,
35282
35574
  visible: pageJumpOpen,
35283
35575
  currentPage,
35284
35576
  pageCount,