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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -20512,6 +20512,42 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20512
20512
  <!-- @papyrus-comic-runtime:end -->
20513
20513
  <script>
20514
20514
  (function () {
20515
+ /* @papyrus-epub-reader:start */
20516
+ (function(root){
20517
+ function mode(value){return value==='chapter-scroll'?'chapter-scroll':'paged';}
20518
+ function validCfi(value){return typeof value==='string' && value.length<=4096 && /^epubcfi\\([^\\n<>]+\\)$/.test(value);}
20519
+ function options(value){return {manager:'default',flow:mode(value)==='paged'?'paginated':'scrolled-doc',spread:'none',width:'100%',height:'100%',allowScriptedContent:false};}
20520
+ function gesture(start,end,state){
20521
+ if(!start || !end || state.selected || state.interactive || state.multitouch)return null;
20522
+ var dx=end.x-start.x,dy=end.y-start.y,elapsed=end.time-start.time;
20523
+ if(state.mode==='paged' && Math.abs(dx)>=48 && Math.abs(dx)>Math.abs(dy)*1.5 && elapsed>=0 && elapsed<1500)return (dx<0)!==Boolean(state.rtl)?'next':'prev';
20524
+ if(elapsed>=0 && elapsed<450 && Math.hypot(dx,dy)<=12)return 'tap';
20525
+ return null;
20526
+ }
20527
+ function location(raw,count,readingMode){
20528
+ var start=raw && raw.start;if(!start || !validCfi(start.cfi))return null;
20529
+ var displayed=start.displayed||{},chapter=Math.max(1,(Number(start.index)||0)+1);
20530
+ var visualPage=mode(readingMode)==='paged' && Number.isFinite(displayed.page)?displayed.page:null;
20531
+ var total=mode(readingMode)==='paged' && Number.isFinite(displayed.total)?displayed.total:null;
20532
+ var fraction=total?Math.max(0,(visualPage-1)/total):0;
20533
+ return {version:1,cfi:start.cfi,href:start.href||'',chapter:chapter,chapterCount:count,visualPage:visualPage,visualPageCount:total,progress:Math.min(1,Math.max(0,(chapter-1+fraction)/Math.max(1,count))),mode:mode(readingMode),atStart:Boolean(raw.atStart),atEnd:Boolean(raw.atEnd)};
20534
+ }
20535
+ function install(contents,config){
20536
+ var doc=contents.document,win=contents.window,start=null,blocked=false;
20537
+ function point(e){var t=e.changedTouches&&e.changedTouches[0]||e.touches&&e.touches[0];return t?{x:t.clientX,y:t.clientY,time:Date.now()}:null;}
20538
+ function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
20539
+ function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
20540
+ function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
20541
+ function move(e){if(e.touches.length!==1)blocked=true;}
20542
+ function end(e){var action=gesture(start,point(e),{mode:config.mode(),rtl:config.rtl(),selected:selected(),interactive:blocked||interactive(e.target)||Boolean(config.annotationHit && config.annotationHit(point(e))),multitouch:blocked});start=null;if(!config.current())return;if(action==='tap')config.tap();else if(action)config.turn(action==='next'?1:-1);}
20543
+ function cancel(){start=null;blocked=true;}
20544
+ doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});
20545
+ return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);};
20546
+ }
20547
+ root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,install:install};
20548
+ })(typeof window==='undefined'?globalThis:window);
20549
+
20550
+ /* @papyrus-epub-reader:end */
20515
20551
  /* @papyrus-epub-annotations:start */
20516
20552
  (function (root, factory) {
20517
20553
  if (typeof module === 'object' && module.exports) module.exports = factory();
@@ -20590,6 +20626,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20590
20626
  var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
20591
20627
  var style = annotation.markupStyle || annotation.type;
20592
20628
  var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
20629
+ if(style === 'highlight')opacity=Math.min(0.35,opacity);
20593
20630
  rects.forEach(function(rect) {
20594
20631
  var mark = doc.createElement('div');
20595
20632
  var bodyRect=doc.body.getBoundingClientRect();
@@ -20602,8 +20639,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20602
20639
  if (hasNote) {
20603
20640
  var last = rects[rects.length-1], button = doc.createElement('button');
20604
20641
  button.textContent = '\u25CF'; button.setAttribute('aria-label',options.labels().comment || '');
20605
- button.style.cssText = 'position:absolute;pointer-events:auto;border:0;background:transparent;color:'+color+';width:44px;height:44px;left:'+Math.max(0,Math.min(doc.documentElement.clientWidth-44,last.right-doc.body.getBoundingClientRect().left))+'px;top:'+(Math.floor(last.top/44)*44-doc.body.getBoundingClientRect().top)+'px';
20606
- var key = Math.floor(last.top/44);
20642
+ var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
20643
+ var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
20644
+ button.style.cssText = 'position:absolute;pointer-events:auto;border:0;background:transparent;color:'+color+';width:44px;height:44px;left:'+((column+1)*pageWidth-44)+'px;top:'+(Math.floor(last.top/44)*44-doc.body.getBoundingClientRect().top)+'px';
20645
+ var key = column+":"+Math.floor(last.top/44);
20607
20646
  var neighbors=noteGroups.get(key);
20608
20647
  if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
20609
20648
  neighbors.ids.push(annotation.id);
@@ -20624,10 +20663,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20624
20663
  doc.addEventListener('click',tapMarkup);
20625
20664
  var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
20626
20665
  if (observer) observer.observe(doc.body);
20627
- win.addEventListener('resize',schedule); doc.addEventListener('load',schedule,true);
20666
+ win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
20628
20667
  if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
20629
20668
  schedule();
20630
- return {schedule:schedule, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
20669
+ return {schedule:schedule, hit:function(x,y){return hitRegions.some(function(item){return item.rects.some(function(r){return x>=r.left && x<=r.right && y>=r.top && y<=r.bottom;});});}, range:function(anchor){return resolveRange(contents,anchor);}, destroy:function(){alive=false;if(frame)win.cancelAnimationFrame(frame);if(observer)observer.disconnect();win.removeEventListener('resize',schedule);win.removeEventListener('scroll',schedule);doc.removeEventListener('load',schedule,true);doc.removeEventListener('click',tapMarkup);overlay.remove();doc.body.style.position=originalPosition;registry.clear();}};
20631
20670
  }
20632
20671
  return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
20633
20672
  });
@@ -21708,26 +21747,55 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21708
21747
  pageCount,
21709
21748
  });
21710
21749
 
21750
+ if (book.locations?.generate) {
21751
+ const activeBook=book;
21752
+ activeBook.locations.generate(150).then(() => {
21753
+ if (isCurrentLoad() && activeBook===book && epubLocation) {
21754
+ epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
21755
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21756
+ }
21757
+ }).catch(() => {});
21758
+ }
21759
+ return renderEpubRendition(loadId,generation,null);
21760
+ };
21761
+
21762
+ const renderEpubRendition = async (loadId,generation,target) => {
21763
+ const diagnosticPayload={loadId};
21764
+ const isCurrentLoad=()=>generation===epubLoadGeneration;
21765
+ if(epubInteractionCleanup)epubInteractionCleanup();
21766
+ if(rendition)rendition.destroy();
21711
21767
  clearViewer();
21712
- rendition = book.renderTo(viewer, {
21713
- manager: 'continuous',
21714
- allowScriptedContent: false,
21715
- width: '100%',
21716
- height: '100%',
21717
- flow: 'scrolled-continuous',
21718
- spread: 'none',
21719
- });
21768
+ rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
21720
21769
  sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
21721
21770
 
21722
21771
  if (rendition && rendition.hooks && rendition.hooks.content) {
21723
21772
  const session = documentSessionId;
21724
21773
  const activeRendition = rendition;
21725
21774
  rendition.hooks.content.register((contents) => {
21775
+ const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
21776
+ mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
21777
+ rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
21778
+ blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
21779
+ annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
21780
+ current: () => session === documentSessionId && activeRendition === rendition,
21781
+ tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
21782
+ turn: direction => {
21783
+ epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
21784
+ if(session !== documentSessionId || activeRendition !== rendition)return;
21785
+ return direction<0?activeRendition.prev():activeRendition.next();
21786
+ });
21787
+ epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
21788
+ },
21789
+ });
21790
+ const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
21791
+ epubSelectionCleanups.add(gestureCleanup);
21792
+ contents.__papyrusGestureCleanup=gestureCleanup;
21726
21793
  const href = spineItems[contents.sectionIndex]?.href;
21727
21794
  if (href && window.PapyrusEpubAnnotations) {
21728
21795
  const renderer = window.PapyrusEpubAnnotations.install(contents, {
21729
21796
  href, get documentId() { return annotationDocumentId; },
21730
21797
  isCurrent: () => session === documentSessionId && activeRendition === rendition,
21798
+ pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
21731
21799
  annotations: () => epubAnnotations, labels: () => annotationLabels,
21732
21800
  onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
21733
21801
  });
@@ -21746,8 +21814,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21746
21814
  typeof selectionWindow.getSelection === 'function'
21747
21815
  ) {
21748
21816
  let selectionTimer = null;
21749
- let lastSelectionKey = '';
21750
- let lastSelectionAt = 0;
21817
+
21751
21818
  const reportSelection = () => {
21752
21819
  selectionTimer = null;
21753
21820
  if (session !== documentSessionId || activeRendition !== rendition) return;
@@ -21762,11 +21829,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21762
21829
  try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
21763
21830
  const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
21764
21831
  if (!anchor) return;
21765
- const key = anchor.cfiRange + ':' + anchor.quote;
21766
- const now = Date.now();
21767
- if (key === lastSelectionKey && now - lastSelectionAt < 750) return;
21768
- lastSelectionKey = key;
21769
- lastSelectionAt = now;
21832
+ if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21770
21833
  const payload = {documentSessionId: session, text: anchor.quote,
21771
21834
  pageIndex: contents.sectionIndex + 1, anchor};
21772
21835
  nativeMenuSelection = {contents, payload};
@@ -21781,6 +21844,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21781
21844
  // The content document still emits selectionchange, so resolve its
21782
21845
  // live Range to a CFI before the native menu action can fire.
21783
21846
  if (text) reportSelection();
21847
+ else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
21784
21848
  };
21785
21849
  selectionDocument.addEventListener('selectionchange', handleSelectionChange);
21786
21850
  const selectionCleanup = () => {
@@ -21803,6 +21867,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21803
21867
  typeof rendition.hooks.unloaded.register === 'function'
21804
21868
  ) {
21805
21869
  rendition.hooks.unloaded.register((view) => {
21870
+ view?.contents?.__papyrusGestureCleanup?.();
21806
21871
  const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
21807
21872
  if (typeof cleanup === 'function') cleanup();
21808
21873
  const renderer = epubAnnotationRenderers.get(view?.contents);
@@ -21818,13 +21883,13 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21818
21883
  if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21819
21884
  const href = spineItems[contents.sectionIndex]?.href;
21820
21885
  const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
21821
- if (!anchor) return;
21886
+ if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21822
21887
  epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
21823
21888
  const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
21824
21889
  nativeMenuSelection = {contents, payload};
21825
21890
  sendEvent('EPUB_TEXT_SELECTED', payload);
21826
21891
  });
21827
- ['rendered','resized','layout'].forEach(name => rendition.on(name, () => {
21892
+ ['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
21828
21893
  if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
21829
21894
  }));
21830
21895
  rendition.on('relocated', (location) => {
@@ -21834,6 +21899,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21834
21899
  if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
21835
21900
  if (index < 0 || index >= spineItems.length) return;
21836
21901
  epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
21902
+ epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll');
21903
+ if(epubLocation){
21904
+ if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
21905
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21906
+ }
21837
21907
  const nextPage = index + 1;
21838
21908
  if (nextPage === currentPage) return;
21839
21909
  currentPage = nextPage;
@@ -21841,9 +21911,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21841
21911
  });
21842
21912
  }
21843
21913
 
21914
+ applyEpubZoom();
21844
21915
  sendEpubDiagnostic('epub.display.start', diagnosticPayload);
21845
21916
  await withEpubStageTimeout(
21846
- displayEpubPage(0),
21917
+ rendition.display(target || spineItems[0]?.href),
21847
21918
  'rendition.display',
21848
21919
  diagnosticPayload,
21849
21920
  );
@@ -21855,7 +21926,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21855
21926
  typeof rendition.manager.on === 'function' &&
21856
21927
  typeof rendition.on === 'function'
21857
21928
  ) {
21858
- let touchStart = null;
21859
21929
  let lastScrollOffset = -1;
21860
21930
  const manager = rendition.manager;
21861
21931
  epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
@@ -21930,57 +22000,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21930
22000
  return result;
21931
22001
  };
21932
22002
  }
21933
- const getTouchPoint = (event) => {
21934
- const touch =
21935
- (event && event.changedTouches && event.changedTouches[0]) ||
21936
- (event && event.touches && event.touches[0]);
21937
- if (!touch) return null;
21938
- const x = Number(touch.screenX ?? touch.clientX);
21939
- const y = Number(touch.screenY ?? touch.clientY);
21940
- return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
21941
- };
21942
- const handleScroll = (event) => {
22003
+ const handleScroll = event => {
21943
22004
  const offsetY = Math.max(0, Number(event && event.top) || 0);
21944
22005
  epubScrollDiagnostics && epubScrollDiagnostics.scroll(event);
21945
- if (Math.abs(offsetY - lastScrollOffset) < 1) return;
21946
- lastScrollOffset = offsetY;
21947
- sendEvent('VIEWER_SCROLL', { offsetY });
21948
- };
21949
- const handleTouchStart = (event) => {
21950
- touchStart = event?.touches?.length > 1 ? null : getTouchPoint(event);
21951
- epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
22006
+ if (Math.abs(offsetY-lastScrollOffset)<1) return;
22007
+ lastScrollOffset=offsetY;
22008
+ sendEvent('VIEWER_SCROLL',{offsetY});
21952
22009
  };
21953
- const handleTouchMove = (event) => {
21954
- if (event?.touches?.length > 1) touchStart = null;
21955
- epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
21956
- };
21957
- const handleTouchEnd = (event) => {
21958
- const end = getTouchPoint(event);
21959
- const start = touchStart;
21960
- touchStart = null;
21961
- const selectedText = event?.target?.ownerDocument?.defaultView?.getSelection?.()?.toString().trim() || '';
21962
- if (!selectedText && start && end && epubViewMode === 'single' && Math.abs(end.x-start.x) >= 48 && Math.abs(end.x-start.x) > Math.abs(end.y-start.y)*1.5) {
21963
- const active = rendition;
21964
- const interactionSession = documentSessionId;
21965
- epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
21966
- if (active !== rendition || interactionSession !== documentSessionId) return;
21967
- return end.x < start.x ? active.next() : active.prev();
21968
- });
21969
- epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR', {message:String(error)}));
21970
- } else if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
21971
- sendEvent('VIEWER_TAP', {});
21972
- }
21973
- epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
21974
- };
21975
-
21976
22010
  manager.on('scroll', handleScroll);
21977
22011
  const handleScrolled = (event) => {
21978
22012
  epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
21979
22013
  };
21980
22014
  manager.on('scrolled', handleScrolled);
21981
- rendition.on('touchstart', handleTouchStart);
21982
- rendition.on('touchmove', handleTouchMove);
21983
- rendition.on('touchend', handleTouchEnd);
22015
+
21984
22016
  epubInteractionCleanup = () => {
21985
22017
  epubSelectionCleanups.forEach((cleanup) => cleanup());
21986
22018
  epubSelectionCleanups.clear();
@@ -21989,16 +22021,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21989
22021
  if (originalEnqueue) queue.enqueue = originalEnqueue;
21990
22022
  if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
21991
22023
  if (typeof manager.off === 'function') manager.off('scrolled', handleScrolled);
21992
- if (typeof rendition.off === 'function') {
21993
- rendition.off('touchstart', handleTouchStart);
21994
- rendition.off('touchmove', handleTouchMove);
21995
- rendition.off('touchend', handleTouchEnd);
21996
- }
21997
22024
  epubScrollDiagnostics = null;
21998
22025
  };
21999
22026
  }
22000
- applyEpubZoom();
22001
-
22002
22027
  const outline = await withEpubStageTimeout(
22003
22028
  buildOutline(),
22004
22029
  'outline',
@@ -22136,7 +22161,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22136
22161
  };
22137
22162
 
22138
22163
  let nativeMenuSelection = null;
22139
- let epubViewMode = "continuous";
22164
+ let epubViewMode = "single";
22165
+ let epubLocation = null;
22140
22166
 
22141
22167
  const handleCommand = async (message) => {
22142
22168
  const { id, kind, payload } = message;
@@ -22149,7 +22175,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22149
22175
  epubAnnotations = [];
22150
22176
  annotationDocumentId = undefined;
22151
22177
  zoom = 1.0;
22152
- epubViewMode = "continuous";
22178
+ epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
22179
+ epubLocation = null;
22180
+ nativeMenuSelection = null;
22153
22181
  epubNavigationRequest += 1;
22154
22182
  epubNavigationQueue = Promise.resolve();
22155
22183
 
@@ -22263,25 +22291,40 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22263
22291
 
22264
22292
  if (kind === 'set-epub-view-mode') {
22265
22293
  if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
22266
- epubViewMode = payload.viewMode === 'single' ? 'single' : 'continuous';
22267
- const active = rendition;
22268
- epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22269
- if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22270
- const flow = epubViewMode === 'single' ? 'paginated' : 'scrolled-continuous';
22271
- if (active.settings.flow === flow) return;
22272
- active.flow(flow);
22273
- return active.q.enqueue(() => Promise.resolve());
22274
- });
22275
- await epubNavigationQueue;
22276
- sendResponse(id,true,null); return;
22294
+ const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
22295
+ {
22296
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22297
+ if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
22298
+ const target=epubLocation?.cfi;
22299
+ epubViewMode=next;
22300
+ await renderEpubRendition('layout',epubLoadGeneration,target);
22301
+ });
22302
+ await epubNavigationQueue;
22303
+ }
22304
+ sendResponse(id,true,null);return;
22305
+ }
22306
+ if(kind === 'epub-go-to-location'){
22307
+ if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
22308
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>payload.documentSessionId===documentSessionId?rendition.display(payload.cfi):undefined);
22309
+ await epubNavigationQueue;sendResponse(id,true,null);return;
22277
22310
  }
22278
22311
 
22279
22312
  if (kind === 'set-zoom') {
22280
- zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
22281
- applyZoom();
22282
- sendState();
22283
- sendResponse(id, true, { zoom });
22284
- return;
22313
+ const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
22314
+ if(currentType === 'epub') {
22315
+ const session=documentSessionId;
22316
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22317
+ if(session!==documentSessionId)return;
22318
+ const active=rendition;
22319
+ const cfi=epubLocation?.cfi;
22320
+ zoom=requestedZoom;applyEpubZoom();
22321
+ // Let the content CSS update before redisplaying the logical anchor.
22322
+ await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
22323
+ if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
22324
+ });
22325
+ await epubNavigationQueue;
22326
+ } else {zoom=requestedZoom;applyZoom();}
22327
+ sendState();sendResponse(id,true,{zoom});return;
22285
22328
  }
22286
22329
 
22287
22330
  if (kind === 'set-rotation') {
@@ -23457,6 +23500,7 @@ var IconToolStrikeout = ({
23457
23500
  ),
23458
23501
  /* @__PURE__ */ jsx2(Rect, { x: "10.9", y: "17.1", width: "14.2", height: "2.4", rx: "1.2", fill: color })
23459
23502
  ] });
23503
+ var IconStrikeout = ({ size = 22, color = defaultColor, strokeWidth = 1.8 }) => /* @__PURE__ */ jsx2(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx2(Path, { d: "M17 5c-1-1-3-2-5-2-3 0-5 2-5 4 0 2 2 3 5 4M17 15c0 2-2 4-5 4-2 0-4-1-5-2M4 12h16", stroke: color, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }) });
23460
23504
  var IconCopy = ({
23461
23505
  size = 20,
23462
23506
  color = defaultColor,
@@ -23521,6 +23565,39 @@ var IconToolNote = ({
23521
23565
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "14.8", x2: "21.6", y2: "14.8", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" }),
23522
23566
  /* @__PURE__ */ jsx2(Line, { x1: "15", y1: "18.2", x2: "19.2", y2: "18.2", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" })
23523
23567
  ] });
23568
+ var IconHighlight = ({
23569
+ size = 24,
23570
+ color = "#fbbf24"
23571
+ }) => /* @__PURE__ */ jsxs(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
23572
+ /* @__PURE__ */ jsx2(
23573
+ Path,
23574
+ {
23575
+ d: "M4 15h16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3Z",
23576
+ fill: color,
23577
+ opacity: "0.85"
23578
+ }
23579
+ ),
23580
+ /* @__PURE__ */ jsx2(
23581
+ Path,
23582
+ {
23583
+ d: "M6 5h12v10H6V5Z",
23584
+ stroke: color,
23585
+ strokeWidth: "2",
23586
+ strokeLinecap: "round",
23587
+ strokeLinejoin: "round",
23588
+ fill: "none"
23589
+ }
23590
+ ),
23591
+ /* @__PURE__ */ jsx2(
23592
+ Path,
23593
+ {
23594
+ d: "M8 8h8M8 11h5",
23595
+ stroke: color,
23596
+ strokeWidth: "2",
23597
+ strokeLinecap: "round"
23598
+ }
23599
+ )
23600
+ ] });
23524
23601
  var IconUnderline = ({
23525
23602
  size = 24,
23526
23603
  color = "#60a5fa",
@@ -25731,6 +25808,39 @@ var styles = StyleSheet.create({
25731
25808
  var arePageRendererPropsEqual = (previous, next) => previous.documentId === next.documentId && previous.engine === next.engine && previous.pageIndex === next.pageIndex && previous.scale === next.scale && previous.PageViewComponent === next.PageViewComponent && previous.availableWidth === next.availableWidth && previous.maxPageWidth === next.maxPageWidth && previous.maxPageHeight === next.maxPageHeight && previous.pageViewportWidth === next.pageViewportWidth && previous.horizontalPadding === next.horizontalPadding && previous.spacing === next.spacing && previous.onSelectionDragActiveChange === next.onSelectionDragActiveChange && previous.gestureScrollLockActive === next.gestureScrollLockActive && previous.lastPinchEndedAt === next.lastPinchEndedAt && previous.requestSelectionVerticalAutoscroll === next.requestSelectionVerticalAutoscroll;
25732
25809
  var PageRenderer_default = memo(PageRenderer, arePageRendererPropsEqual);
25733
25810
 
25811
+ // components/PapyrusSafeArea.tsx
25812
+ import React3, { useContext as useContext2 } from "react";
25813
+ import {
25814
+ SafeAreaInsetsContext,
25815
+ SafeAreaProvider
25816
+ } from "react-native-safe-area-context";
25817
+ import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
25818
+ var papyrusSafeAreaContext = SafeAreaInsetsContext;
25819
+ var ZERO_SAFE_AREA_INSETS = {
25820
+ top: 0,
25821
+ bottom: 0,
25822
+ left: 0,
25823
+ right: 0
25824
+ };
25825
+ var usePapyrusSafeAreaInsets = () => useContext2(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
25826
+ function PapyrusSafeAreaBoundary({
25827
+ children
25828
+ }) {
25829
+ const insets = useContext2(papyrusSafeAreaContext);
25830
+ if (insets) return /* @__PURE__ */ jsx4(Fragment, { children });
25831
+ return React3.createElement(SafeAreaProvider, null, children);
25832
+ }
25833
+
25834
+ // components/epubReadingLocation.ts
25835
+ function parseEpubReadingLocation(raw) {
25836
+ if (!raw || typeof raw !== "object") return null;
25837
+ const p = raw;
25838
+ if (p.version !== 1 || typeof p.cfi !== "string" || p.cfi.length > 4096 || !/^epubcfi\([^\n<>]+\)$/.test(p.cfi) || typeof p.href !== "string" || !Number.isSafeInteger(p.chapter) || p.chapter < 1 || !Number.isSafeInteger(p.chapterCount) || p.chapterCount < p.chapter || !Number.isFinite(p.progress) || p.progress < 0 || p.progress > 1 || typeof p.atStart !== "boolean" || typeof p.atEnd !== "boolean") return null;
25839
+ if (p.mode === "chapter-scroll") return p.visualPage === null && p.visualPageCount === null ? p : null;
25840
+ if (p.mode !== "paged" || !Number.isSafeInteger(p.visualPage) || (p.visualPage ?? 0) < 1 || !Number.isSafeInteger(p.visualPageCount) || (p.visualPageCount ?? 0) < (p.visualPage ?? 0)) return null;
25841
+ return p;
25842
+ }
25843
+
25734
25844
  // components/WebViewViewer.tsx
25735
25845
  import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
25736
25846
  import { Image, StyleSheet as StyleSheet2, View as View2, Alert } from "react-native";
@@ -25800,7 +25910,7 @@ function parseEpubAnnotationEvent(raw, session, documentId) {
25800
25910
  }
25801
25911
 
25802
25912
  // components/WebViewViewer.tsx
25803
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
25913
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
25804
25914
  var runtimeAsset = require_runtime();
25805
25915
  var resolveRuntimeSource = (asset) => {
25806
25916
  if (typeof asset === "string") {
@@ -25820,6 +25930,7 @@ var resolveRuntimeSource = (asset) => {
25820
25930
  };
25821
25931
  var WebViewViewer = ({
25822
25932
  engine,
25933
+ documentType,
25823
25934
  documentId,
25824
25935
  onDefineSelection,
25825
25936
  defineSelectionMode,
@@ -25828,7 +25939,8 @@ var WebViewViewer = ({
25828
25939
  onTap
25829
25940
  }) => {
25830
25941
  const webViewRef = useRef2(null);
25831
- const { pageTheme, viewMode, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25942
+ const insets = usePapyrusSafeAreaInsets();
25943
+ const { pageTheme, epubReadingMode, setDocumentState, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = useViewerStore2();
25832
25944
  const [selection, setSelection] = useState2(null);
25833
25945
  const t = getStrings(locale);
25834
25946
  const bridgeEngine = engine;
@@ -25911,8 +26023,8 @@ var WebViewViewer = ({
25911
26023
  };
25912
26024
  useEffect2(() => {
25913
26025
  if (!isLoaded) return;
25914
- webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { viewMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
25915
- }, [isLoaded, viewMode, bridgeEngine]);
26026
+ webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { epubMode: epubReadingMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26027
+ }, [isLoaded, epubReadingMode, bridgeEngine]);
25916
26028
  const sendSelectionCommand = (key) => {
25917
26029
  webViewRef.current?.postMessage(JSON.stringify({
25918
26030
  type: "epub-selection-action",
@@ -25936,6 +26048,11 @@ var WebViewViewer = ({
25936
26048
  let annotationRaw = raw;
25937
26049
  try {
25938
26050
  const message = JSON.parse(raw);
26051
+ if (message.type === "event" && message.name === "EPUB_LOCATION" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) {
26052
+ const location = parseEpubReadingLocation(message.payload.location);
26053
+ if (location) setDocumentState({ epubLocation: location });
26054
+ }
26055
+ if (message.type === "event" && message.name === "EPUB_CONTENT_TAP" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) onTap?.();
25939
26056
  if (message.type === "event" && message.name === "EPUB_SELECTION_ACTION") {
25940
26057
  action = message.payload?.action;
25941
26058
  annotationRaw = JSON.stringify({ ...message, name: "EPUB_TEXT_SELECTED" });
@@ -26024,8 +26141,8 @@ var WebViewViewer = ({
26024
26141
  maxWidth: resolvedMaxPageWidth,
26025
26142
  alignSelf: "center"
26026
26143
  } : void 0;
26027
- return /* @__PURE__ */ jsxs3(View2, { style: styles2.container, children: [
26028
- /* @__PURE__ */ jsx4(
26144
+ return /* @__PURE__ */ jsxs3(View2, { style: [styles2.container, documentType === "epub" && { paddingTop: insets.top, paddingBottom: insets.bottom }], children: [
26145
+ /* @__PURE__ */ jsx5(
26029
26146
  WebView,
26030
26147
  {
26031
26148
  ref: webViewRef,
@@ -26049,7 +26166,7 @@ var WebViewViewer = ({
26049
26166
  style: [styles2.webview, cappedWebViewStyle]
26050
26167
  }
26051
26168
  ),
26052
- /* @__PURE__ */ jsx4(
26169
+ /* @__PURE__ */ jsx5(
26053
26170
  View2,
26054
26171
  {
26055
26172
  pointerEvents: "none",
@@ -26151,16 +26268,16 @@ function getNearbyPdfNotes(annotations, id) {
26151
26268
  // components/PdfNoteChooser.tsx
26152
26269
  import { FlatList, Modal, Pressable as Pressable2, StyleSheet as StyleSheet3, Text, View as View3 } from "react-native";
26153
26270
  import { getAnnotationNote, getAnnotationQuote } from "@papyrus-sdk/core";
26154
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
26271
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
26155
26272
  function PdfNoteChooser({ notes, title, cancel, onSelect, onClose }) {
26156
- 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: [
26157
- /* @__PURE__ */ jsx5(Text, { style: styles3.title, children: title }),
26158
- /* @__PURE__ */ jsx5(FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ jsx5(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ jsxs4(Text, { children: [
26273
+ return /* @__PURE__ */ jsx6(Modal, { visible: notes.length > 1, transparent: true, animationType: "none", onRequestClose: onClose, children: /* @__PURE__ */ jsx6(View3, { style: styles3.backdrop, children: /* @__PURE__ */ jsxs4(View3, { style: styles3.sheet, accessibilityViewIsModal: true, children: [
26274
+ /* @__PURE__ */ jsx6(Text, { style: styles3.title, children: title }),
26275
+ /* @__PURE__ */ jsx6(FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ jsx6(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ jsxs4(Text, { children: [
26159
26276
  index + 1,
26160
26277
  ". ",
26161
26278
  getAnnotationNote(item) || getAnnotationQuote(item)
26162
26279
  ] }) }) }),
26163
- /* @__PURE__ */ jsx5(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx5(Text, { children: cancel }) })
26280
+ /* @__PURE__ */ jsx6(Pressable2, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ jsx6(Text, { children: cancel }) })
26164
26281
  ] }) }) });
26165
26282
  }
26166
26283
  var styles3 = StyleSheet3.create({ backdrop: { flex: 1, backgroundColor: "#0008", justifyContent: "center", padding: 24 }, sheet: { backgroundColor: "#fff", borderRadius: 16, padding: 16, maxHeight: "75%" }, title: { fontSize: 18, fontWeight: "600", marginBottom: 12 }, row: { minHeight: 44, padding: 12 } });
@@ -26187,7 +26304,7 @@ var resolvePageTapChromeVisibility = ({
26187
26304
  };
26188
26305
 
26189
26306
  // components/DedicatedAndroidPdfViewer.tsx
26190
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
26307
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
26191
26308
  var TEXT_MARKUP_TOOLS2 = /* @__PURE__ */ new Set(["highlight", "underline", "squiggly", "strikeout"]);
26192
26309
  var MOBILE_CHROME_HIDE_DELTA = 28;
26193
26310
  var MOBILE_CHROME_SHOW_DELTA = 22;
@@ -26331,11 +26448,11 @@ function DedicatedAndroidPdfViewer({
26331
26448
  selectionRef.current = null;
26332
26449
  }, [addAnnotation, beginAnnotationDraft, annotationColor, documentId]);
26333
26450
  return /* @__PURE__ */ jsxs5(View4, { style: styles4.container, children: [
26334
- /* @__PURE__ */ jsx6(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26451
+ /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26335
26452
  setPendingNotes([]);
26336
26453
  setSelectedAnnotation(id);
26337
26454
  } }),
26338
- /* @__PURE__ */ jsx6(
26455
+ /* @__PURE__ */ jsx7(
26339
26456
  PapyrusPdfDocumentView,
26340
26457
  {
26341
26458
  style: [styles4.viewer, cappedViewerStyle],
@@ -26546,7 +26663,7 @@ var resolveNativePdfVisiblePages = (pages) => (pages ?? []).flatMap((page) => {
26546
26663
  });
26547
26664
 
26548
26665
  // components/DedicatedIosPdfViewer.tsx
26549
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
26666
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
26550
26667
  var MOBILE_CHROME_HIDE_DELTA2 = 28;
26551
26668
  var MOBILE_CHROME_SHOW_DELTA2 = 22;
26552
26669
  var MOBILE_CHROME_SHOW_DELAY_MS2 = 180;
@@ -26785,11 +26902,11 @@ function DedicatedIosPdfViewer({
26785
26902
  alignSelf: "center"
26786
26903
  } : void 0;
26787
26904
  return /* @__PURE__ */ jsxs6(View5, { style: styles5.container, children: [
26788
- /* @__PURE__ */ jsx7(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26905
+ /* @__PURE__ */ jsx8(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26789
26906
  setPendingNotes([]);
26790
26907
  setSelectedAnnotation(id);
26791
26908
  } }),
26792
- /* @__PURE__ */ jsx7(
26909
+ /* @__PURE__ */ jsx8(
26793
26910
  PapyrusPdfDocumentView2,
26794
26911
  {
26795
26912
  style: [styles5.viewer, cappedViewerStyle],
@@ -26858,22 +26975,22 @@ function DedicatedIosPdfViewer({
26858
26975
  onInkToolPickerVisibilityChange: handleInkToolPickerVisibilityChange
26859
26976
  }
26860
26977
  ),
26861
- selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx7(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx7(
26978
+ selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ jsx8(View5, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ jsx8(
26862
26979
  Pressable3,
26863
26980
  {
26864
26981
  onPress: defineSelection,
26865
26982
  style: styles5.fallbackButton,
26866
26983
  accessibilityRole: "button",
26867
26984
  accessibilityLabel: t.define,
26868
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.fallbackButtonText, children: t.define })
26985
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.fallbackButtonText, children: t.define })
26869
26986
  }
26870
26987
  ) }),
26871
- fallbackDeleteAnnotation && /* @__PURE__ */ jsx7(
26988
+ fallbackDeleteAnnotation && /* @__PURE__ */ jsx8(
26872
26989
  View5,
26873
26990
  {
26874
26991
  style: styles5.annotationDeleteFallback,
26875
26992
  pointerEvents: "box-none",
26876
- children: /* @__PURE__ */ jsx7(
26993
+ children: /* @__PURE__ */ jsx8(
26877
26994
  Pressable3,
26878
26995
  {
26879
26996
  onPress: () => handleDeleteAnnotation(fallbackDeleteAnnotation.id),
@@ -26881,7 +26998,7 @@ function DedicatedIosPdfViewer({
26881
26998
  accessibilityRole: "button",
26882
26999
  accessibilityLabel: t.deleteAnnotation,
26883
27000
  hitSlop: 8,
26884
- children: /* @__PURE__ */ jsx7(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
27001
+ children: /* @__PURE__ */ jsx8(Text2, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
26885
27002
  }
26886
27003
  )
26887
27004
  }
@@ -26944,7 +27061,7 @@ var styles5 = StyleSheet5.create({
26944
27061
  });
26945
27062
 
26946
27063
  // components/NativePdfDocumentViewer.tsx
26947
- import { jsx as jsx8 } from "react/jsx-runtime";
27064
+ import { jsx as jsx9 } from "react/jsx-runtime";
26948
27065
  function NativePdfDocumentViewer({
26949
27066
  engine,
26950
27067
  documentId,
@@ -26957,7 +27074,7 @@ function NativePdfDocumentViewer({
26957
27074
  Platform3.OS
26958
27075
  );
26959
27076
  if (implementation === "android") {
26960
- return /* @__PURE__ */ jsx8(
27077
+ return /* @__PURE__ */ jsx9(
26961
27078
  DedicatedAndroidPdfViewer,
26962
27079
  {
26963
27080
  engine,
@@ -26970,7 +27087,7 @@ function NativePdfDocumentViewer({
26970
27087
  );
26971
27088
  }
26972
27089
  if (implementation === "ios") {
26973
- return /* @__PURE__ */ jsx8(
27090
+ return /* @__PURE__ */ jsx9(
26974
27091
  DedicatedIosPdfViewer,
26975
27092
  {
26976
27093
  engine,
@@ -27026,29 +27143,6 @@ var resolveMobileChromeOffsets = (insets) => ({
27026
27143
  right: MOBILE_CHROME_METRICS.screenPadding + Math.max(0, insets.right)
27027
27144
  });
27028
27145
 
27029
- // components/PapyrusSafeArea.tsx
27030
- import React6, { useContext as useContext2 } from "react";
27031
- import {
27032
- SafeAreaInsetsContext,
27033
- SafeAreaProvider
27034
- } from "react-native-safe-area-context";
27035
- import { Fragment, jsx as jsx9 } from "react/jsx-runtime";
27036
- var papyrusSafeAreaContext = SafeAreaInsetsContext;
27037
- var ZERO_SAFE_AREA_INSETS = {
27038
- top: 0,
27039
- bottom: 0,
27040
- left: 0,
27041
- right: 0
27042
- };
27043
- var usePapyrusSafeAreaInsets = () => useContext2(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
27044
- function PapyrusSafeAreaBoundary({
27045
- children
27046
- }) {
27047
- const insets = useContext2(papyrusSafeAreaContext);
27048
- if (insets) return /* @__PURE__ */ jsx9(Fragment, { children });
27049
- return React6.createElement(SafeAreaProvider, null, children);
27050
- }
27051
-
27052
27146
  // components/NativeTextDocumentViewer.tsx
27053
27147
  import { jsx as jsx10 } from "react/jsx-runtime";
27054
27148
  function NativeTextDocumentViewer({
@@ -27599,6 +27693,7 @@ var scrollViewerListToOffset = (list, offset, animated) => {
27599
27693
  list.scrollToOffset?.({ offset, animated });
27600
27694
  };
27601
27695
  var Viewer = ({
27696
+ documentType,
27602
27697
  documentId,
27603
27698
  engine,
27604
27699
  maxPageWidth,
@@ -29126,14 +29221,8 @@ var Viewer = ({
29126
29221
  },
29127
29222
  [mobilePerf, perfEnabled, scrollPerfSession]
29128
29223
  );
29129
- const handleWebViewScroll = useCallback4(
29130
- (_offsetY) => {
29131
- if (!chromeVisibleRef.current) {
29132
- setMobileChromeVisible(true, "scroll.webview.recover");
29133
- }
29134
- },
29135
- [setMobileChromeVisible]
29136
- );
29224
+ const handleWebViewScroll = useCallback4((_offsetY) => {
29225
+ }, []);
29137
29226
  const handlePageTap = useCallback4(() => {
29138
29227
  const nextVisible = resolvePageTapChromeVisibility({
29139
29228
  chromeVisible: chromeVisibleRef.current,
@@ -29355,6 +29444,7 @@ var Viewer = ({
29355
29444
  return /* @__PURE__ */ jsx12(View8, { style: [styles8.container, isDark && styles8.containerDark], children: /* @__PURE__ */ jsx12(
29356
29445
  WebViewViewer_default,
29357
29446
  {
29447
+ documentType,
29358
29448
  engine,
29359
29449
  documentId,
29360
29450
  onDefineSelection,
@@ -29925,6 +30015,7 @@ var styles9 = StyleSheet9.create({
29925
30015
  // components/PageJumpModal.tsx
29926
30016
  import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
29927
30017
  function PageJumpModal({
30018
+ documentType,
29928
30019
  visible,
29929
30020
  currentPage,
29930
30021
  pageCount,
@@ -29951,8 +30042,8 @@ function PageJumpModal({
29951
30042
  isDark,
29952
30043
  maxHeight: 300,
29953
30044
  showHeader: true,
29954
- title: "Ir para p\xE1gina",
29955
- closeAccessibilityLabel: "Close page jump",
30045
+ title: documentType === "epub" ? "Ir para cap\xEDtulo" : "Ir para p\xE1gina",
30046
+ closeAccessibilityLabel: "Fechar navega\xE7\xE3o",
29956
30047
  sheetStyle: {
29957
30048
  paddingHorizontal: 18,
29958
30049
  paddingBottom: 18,
@@ -29980,7 +30071,7 @@ function PageJumpModal({
29980
30071
  }
29981
30072
  ],
29982
30073
  onSubmitEditing: confirmJump,
29983
- accessibilityLabel: "Page jump input",
30074
+ accessibilityLabel: documentType === "epub" ? "N\xFAmero do cap\xEDtulo" : "N\xFAmero da p\xE1gina",
29984
30075
  testID: "papyrus-page-jump-input"
29985
30076
  }
29986
30077
  ),
@@ -30035,6 +30126,7 @@ var styles10 = StyleSheet10.create({
30035
30126
  import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
30036
30127
  var Topbar = ({
30037
30128
  engine,
30129
+ documentType,
30038
30130
  onOpenSettings,
30039
30131
  onOpenOverflow,
30040
30132
  title,
@@ -30055,6 +30147,12 @@ var Topbar = ({
30055
30147
  locale
30056
30148
  } = useViewerStore9();
30057
30149
  const inkSession = useNativeInkSession();
30150
+ const chromeVisible = mobileChromeVisible || inkSession.active;
30151
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
30152
+ const chromeMotion = useAnimatedStyle(() => {
30153
+ "worklet";
30154
+ return { opacity: chromeProgress.value };
30155
+ });
30058
30156
  const t = getStrings(locale);
30059
30157
  const progress = useNativeInkMotion(inkSession.active, inkSession.supported);
30060
30158
  const settingsMotion = useAnimatedStyle(() => {
@@ -30110,20 +30208,23 @@ var Topbar = ({
30110
30208
  children: /* @__PURE__ */ jsx15(IconSettings, { size: MOBILE_CHROME_METRICS.iconSize, color: isDark ? "#e5e7eb" : "#111827" })
30111
30209
  }
30112
30210
  );
30113
- if (!mobileChromeVisible && !inkSession.active) return null;
30211
+ if (!chromeVisible && documentType !== "epub") return null;
30114
30212
  return /* @__PURE__ */ jsxs10(Fragment2, { children: [
30115
30213
  /* @__PURE__ */ jsx15(
30116
- View11,
30214
+ Animated3.View,
30117
30215
  {
30118
30216
  style: [
30119
30217
  styles11.chromeFrame,
30218
+ chromeMotion,
30120
30219
  {
30121
30220
  paddingTop: insets.top,
30122
30221
  paddingLeft: MOBILE_CHROME_METRICS.screenPadding + insets.left,
30123
30222
  paddingRight: MOBILE_CHROME_METRICS.screenPadding + insets.right
30124
30223
  }
30125
30224
  ],
30126
- pointerEvents: "box-none",
30225
+ pointerEvents: chromeVisible ? "box-none" : "none",
30226
+ accessibilityElementsHidden: !chromeVisible,
30227
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
30127
30228
  testID: "papyrus-floating-top-controls",
30128
30229
  children: /* @__PURE__ */ jsxs10(
30129
30230
  View11,
@@ -30270,6 +30371,7 @@ var Topbar = ({
30270
30371
  /* @__PURE__ */ jsx15(
30271
30372
  PageJumpModal,
30272
30373
  {
30374
+ documentType,
30273
30375
  visible: jumpModalOpen,
30274
30376
  currentPage,
30275
30377
  pageCount,
@@ -32543,7 +32645,27 @@ var AnnotationEditor = ({ documentId }) => {
32543
32645
  editing ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
32544
32646
  /* @__PURE__ */ jsx18(TextInput2, { accessibilityLabel: t.editNote, value: draft, onChangeText: setDraft, multiline: true, autoFocus: true, placeholder: t.notePlaceholder, placeholderTextColor: dark ? "#9ca3af" : "#6b7280", style: [styles14.input, textStyle, { borderColor: dark ? "#374151" : "#d1d5db" }] }),
32545
32647
  /* @__PURE__ */ jsx18(View14, { style: styles14.options, children: COLORS.map((value) => /* @__PURE__ */ jsx18(Pressable9, { accessibilityRole: "button", accessibilityLabel: `${t.annotationColor} ${value}`, accessibilityState: { selected: color === value }, onPress: () => setColor(value), style: [styles14.color, { backgroundColor: value, borderColor: color === value ? accentColor : "transparent" }] }, value)) }),
32546
- /* @__PURE__ */ jsx18(View14, { style: styles14.options, children: [["highlight", t.annotationHighlight], ["underline", t.annotationUnderline], ["strikeout", t.annotationStrikeout], ["none", t.annotationIndicatorOnly]].map(([style, label]) => /* @__PURE__ */ jsx18(Pressable9, { onPress: () => setMarkup(style), accessibilityRole: "button", accessibilityState: { selected: markup === style }, style: [styles14.button, markup === style && { borderColor: accentColor, borderWidth: 1 }], children: /* @__PURE__ */ jsx18(Text8, { style: textStyle, children: label }) }, style)) })
32648
+ /* @__PURE__ */ jsx18(View14, { style: styles14.markupOptions, children: [
32649
+ ["highlight", t.annotationHighlight, IconHighlight],
32650
+ ["underline", t.annotationUnderline, IconUnderline],
32651
+ ["strikeout", t.annotationStrikeout, IconStrikeout],
32652
+ ["none", t.annotationIndicatorOnly, IconComment]
32653
+ ].map(([style, label, Icon]) => /* @__PURE__ */ jsxs13(
32654
+ Pressable9,
32655
+ {
32656
+ onPress: () => setMarkup(style),
32657
+ accessibilityRole: "button",
32658
+ accessibilityLabel: label,
32659
+ accessibilityState: { selected: markup === style },
32660
+ testID: `annotation-style-${style}`,
32661
+ style: [styles14.markupButton, { backgroundColor: dark ? "#242936" : "#f1f5f9", borderColor: markup === style ? accentColor : "transparent" }],
32662
+ children: [
32663
+ /* @__PURE__ */ jsx18(View14, { accessible: false, importantForAccessibility: "no-hide-descendants", children: /* @__PURE__ */ jsx18(Icon, { size: 22, color: markup === style ? accentColor : textStyle.color }) }),
32664
+ /* @__PURE__ */ jsx18(Text8, { style: [styles14.markupLabel, textStyle], children: style === "none" ? locale === "pt-BR" ? "Indicador" : "Indicator" : label })
32665
+ ]
32666
+ },
32667
+ style
32668
+ )) })
32547
32669
  ] }) : /* @__PURE__ */ jsx18(Text8, { style: [styles14.note, textStyle], selectable: true, children: getAnnotationNote2(annotation) || t.notePlaceholder })
32548
32670
  ] }),
32549
32671
  /* @__PURE__ */ jsxs13(View14, { style: styles14.actions, children: [
@@ -32566,7 +32688,7 @@ var AnnotationEditor = ({ documentId }) => {
32566
32688
  ] })
32567
32689
  ] }) });
32568
32690
  };
32569
- var styles14 = StyleSheet14.create({ host: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,.18)", paddingHorizontal: 12 }, card: { borderRadius: 20, padding: 16, maxHeight: "72%", elevation: 12 }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, title: { fontSize: 17, fontWeight: "700" }, content: { flexGrow: 0 }, quote: { fontSize: 14, lineHeight: 21, borderLeftWidth: 3, borderLeftColor: "#9ca3af", paddingLeft: 10, marginVertical: 12 }, note: { fontSize: 16, lineHeight: 24, paddingVertical: 12 }, input: { minHeight: 112, maxHeight: 240, borderWidth: 1, borderRadius: 12, padding: 12, fontSize: 16, textAlignVertical: "top" }, button: { minWidth: 44, minHeight: 44, paddingHorizontal: 10, borderRadius: 10, alignItems: "center", justifyContent: "center" }, actions: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", marginTop: 12 }, options: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, color: { width: 44, height: 44, borderRadius: 22, borderWidth: 3 } });
32691
+ var styles14 = StyleSheet14.create({ host: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,.18)", paddingHorizontal: 12 }, card: { borderRadius: 20, padding: 16, maxHeight: "72%", elevation: 12 }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, title: { fontSize: 17, fontWeight: "700" }, content: { flexGrow: 0 }, quote: { fontSize: 14, lineHeight: 21, borderLeftWidth: 3, borderLeftColor: "#9ca3af", paddingLeft: 10, marginVertical: 12 }, note: { fontSize: 16, lineHeight: 24, paddingVertical: 12 }, input: { minHeight: 112, maxHeight: 240, borderWidth: 1, borderRadius: 12, padding: 12, fontSize: 16, textAlignVertical: "top" }, button: { minWidth: 44, minHeight: 44, paddingHorizontal: 10, borderRadius: 10, alignItems: "center", justifyContent: "center" }, actions: { flexDirection: "row", alignItems: "center", flexWrap: "wrap", marginTop: 12 }, markupOptions: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, markupButton: { flex: 1, minWidth: 64, minHeight: 64, borderWidth: 1, borderRadius: 12, paddingHorizontal: 4, paddingVertical: 8, alignItems: "center", justifyContent: "center", gap: 6 }, markupLabel: { fontSize: 11, lineHeight: 15, textAlign: "center" }, options: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: 12 }, color: { width: 44, height: 44, borderRadius: 22, borderWidth: 3 } });
32570
32692
  var AnnotationEditor_default = AnnotationEditor;
32571
32693
 
32572
32694
  // components/BottomBar.tsx
@@ -32637,6 +32759,8 @@ var BottomBar = ({
32637
32759
  const {
32638
32760
  activeMobileDestination,
32639
32761
  viewMode,
32762
+ epubReadingMode,
32763
+ epubLocation,
32640
32764
  comicLayoutMode,
32641
32765
  currentPage,
32642
32766
  pageCount,
@@ -32654,7 +32778,7 @@ var BottomBar = ({
32654
32778
  const supportsInkChrome = documentType === "pdf" && inkSession.supported;
32655
32779
  const drawing = supportsInkChrome && inkSession.active;
32656
32780
  const dockVisible = mobileChromeVisible && mobileDockVisible && !drawing;
32657
- const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome);
32781
+ const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome || documentType === "epub");
32658
32782
  const dockMotion = useAnimatedStyle2(() => {
32659
32783
  "worklet";
32660
32784
  return {
@@ -32676,7 +32800,7 @@ var BottomBar = ({
32676
32800
  activeMobileDestination,
32677
32801
  toolDockOpen
32678
32802
  });
32679
- const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : viewMode === "single");
32803
+ const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single");
32680
32804
  if (paginated) {
32681
32805
  layout.leftSlots.push(...layout.rightSlots.filter((slot) => slot.key === "search"));
32682
32806
  layout.rightSlots = [];
@@ -32745,7 +32869,7 @@ var BottomBar = ({
32745
32869
  onPress: onOpenSettings
32746
32870
  }
32747
32871
  };
32748
- if (!dockVisible && !supportsInkChrome) return null;
32872
+ if (!dockVisible && !supportsInkChrome && documentType !== "epub") return null;
32749
32873
  return /* @__PURE__ */ jsx19(
32750
32874
  Animated5.View,
32751
32875
  {
@@ -32811,13 +32935,9 @@ var BottomBar = ({
32811
32935
  ],
32812
32936
  testID: "papyrus-floating-bottom-dock",
32813
32937
  children: paginated ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
32814
- /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "P\xE1gina anterior" : "Previous page", disabled: !dockVisible || !onTurnPage && currentPage <= 1, onPress: () => turnPage(-1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
32815
- /* @__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__ */ jsxs14(Text9, { style: { color: iconColor(false), fontWeight: "700", fontSize: 13, lineHeight: 18, includeFontPadding: false }, children: [
32816
- currentPage,
32817
- "/",
32818
- pageCount
32819
- ] }) }),
32820
- /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Pr\xF3xima p\xE1gina" : "Next page", disabled: !dockVisible || !onTurnPage && currentPage >= pageCount, onPress: () => turnPage(1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
32938
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "P\xE1gina anterior" : "Previous page", disabled: !dockVisible || (documentType === "epub" ? epubLocation?.atStart : !onTurnPage && currentPage <= 1), onPress: () => turnPage(-1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
32939
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Ir para p\xE1gina" : "Go to page", onPress: onOpenPages, style: [styles15.iconOnlyItem, { minWidth: 56 }], children: /* @__PURE__ */ jsx19(Text9, { style: { color: iconColor(false), fontWeight: "700", fontSize: 13, lineHeight: 18, includeFontPadding: false }, children: documentType === "epub" ? epubLocation?.visualPage ? `Cap. ${epubLocation.chapter} \xB7 ${epubLocation.visualPage}/${epubLocation.visualPageCount}` : `Cap. ${currentPage}` : `${currentPage}/${pageCount}` }) }),
32940
+ /* @__PURE__ */ jsx19(Pressable10, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Pr\xF3xima p\xE1gina" : "Next page", disabled: !dockVisible || (documentType === "epub" ? epubLocation?.atEnd : !onTurnPage && currentPage >= pageCount), onPress: () => turnPage(1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ jsx19(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
32821
32941
  ] }) : layout.rightSlots.map((slot) => {
32822
32942
  const meta = slotMeta[slot.key];
32823
32943
  const Icon = meta.icon;
@@ -32999,6 +33119,7 @@ var SettingsSheet = ({
32999
33119
  }) => {
33000
33120
  const {
33001
33121
  viewMode,
33122
+ epubReadingMode,
33002
33123
  uiTheme,
33003
33124
  zoom,
33004
33125
  setDocumentState,
@@ -33010,12 +33131,16 @@ var SettingsSheet = ({
33010
33131
  comicReadingDirection
33011
33132
  } = useViewerStore14();
33012
33133
  const isDark = uiTheme === "dark";
33013
- const isPaged = viewMode === "single";
33134
+ const isPaged = documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single";
33014
33135
  const isDouble = viewMode === "double";
33015
33136
  const t = getStrings(locale);
33016
33137
  const { height: windowHeight } = useWindowDimensions8();
33017
33138
  const sheetMaxHeight = getSettingsSheetMaxHeight(windowHeight);
33018
33139
  const handleTransition = (mode) => {
33140
+ if (documentType === "epub") {
33141
+ setDocumentState({ epubReadingMode: mode === "paged" ? "paged" : "chapter-scroll" });
33142
+ return;
33143
+ }
33019
33144
  if (mode === "paged") {
33020
33145
  setDocumentState({ viewMode: "single" });
33021
33146
  return;
@@ -33239,7 +33364,7 @@ var SettingsSheet = ({
33239
33364
  isDark && styles16.optionTextDark,
33240
33365
  (!isPaged || isDouble) && styles16.optionTextActive
33241
33366
  ],
33242
- children: t.continuous
33367
+ children: documentType === "epub" && locale === "pt-BR" ? "Rolagem por cap\xEDtulo" : t.continuous
33243
33368
  }
33244
33369
  )
33245
33370
  }
@@ -33269,7 +33394,7 @@ var SettingsSheet = ({
33269
33394
  )
33270
33395
  ] })
33271
33396
  ] }),
33272
- documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33397
+ documentType === "pdf" && /* @__PURE__ */ jsxs15(View16, { style: styles16.section, children: [
33273
33398
  /* @__PURE__ */ jsx20(
33274
33399
  Text10,
33275
33400
  {
@@ -34162,6 +34287,7 @@ import {
34162
34287
  View as View21,
34163
34288
  useWindowDimensions as useWindowDimensions9
34164
34289
  } from "react-native";
34290
+ import Reanimated, { useAnimatedStyle as useAnimatedStyle3 } from "react-native-reanimated";
34165
34291
  import { useViewerStore as useViewerStore18 } from "@papyrus-sdk/core";
34166
34292
 
34167
34293
  // components/progressPillMode.ts
@@ -34195,12 +34321,20 @@ function ProgressPill({
34195
34321
  textLength,
34196
34322
  comicLayoutMode,
34197
34323
  viewMode,
34324
+ epubReadingMode,
34325
+ epubLocation,
34198
34326
  locale,
34199
34327
  uiTheme,
34200
34328
  accentColor,
34201
34329
  mobileChromeVisible,
34202
34330
  mobileProgressPillVisible
34203
34331
  } = useViewerStore18();
34332
+ const chromeVisible = mobileChromeVisible && mobileProgressPillVisible;
34333
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
34334
+ const chromeMotion = useAnimatedStyle3(() => {
34335
+ "worklet";
34336
+ return { opacity: chromeProgress.value };
34337
+ });
34204
34338
  const t = getStrings(locale);
34205
34339
  const isDark = uiTheme === "dark";
34206
34340
  const offsets = resolveMobileChromeOffsets(usePapyrusSafeAreaInsets());
@@ -34245,10 +34379,10 @@ function ProgressPill({
34245
34379
  return `${displayedPage}/${pageCount || 0}`;
34246
34380
  }
34247
34381
  if (documentType === "epub") {
34248
- return `Cap. ${displayedPage} \xB7 ${percent}%`;
34382
+ return `Cap. ${displayedPage} \xB7 ${scrubPreviewPage === null && epubLocation ? clampPercent(epubLocation.progress * 100) : percent}%`;
34249
34383
  }
34250
34384
  return `${percent}%`;
34251
- }, [displayedPage, documentType, pageCount]);
34385
+ }, [displayedPage, documentType, pageCount, epubLocation, scrubPreviewPage]);
34252
34386
  const thumbTop = resolvePageScrubberThumbTop({
34253
34387
  currentPage,
34254
34388
  trackHeight,
@@ -34290,7 +34424,7 @@ function ProgressPill({
34290
34424
  },
34291
34425
  []
34292
34426
  );
34293
- if (!shouldRenderPageScrubber({
34427
+ if (!(documentType === "epub" && mobileProgressPillVisible) && !shouldRenderPageScrubber({
34294
34428
  mobileChromeVisible,
34295
34429
  mobileProgressPillVisible,
34296
34430
  isScrubbing: isScrubbingRef.current
@@ -34321,7 +34455,7 @@ function ProgressPill({
34321
34455
  }
34322
34456
  );
34323
34457
  }
34324
- const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : viewMode;
34458
+ const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : documentType === "epub" ? epubReadingMode === "paged" ? "single" : "continuous" : viewMode;
34325
34459
  const pillMode = resolveProgressPillMode(progressViewMode, currentPage, pageCount);
34326
34460
  if (pillMode.kind === "navigation" && navigationInDock) return null;
34327
34461
  if (pillMode.kind === "navigation") {
@@ -34512,11 +34646,14 @@ function ProgressPill({
34512
34646
  }
34513
34647
  const responderPanHandlers = scrubberResponderRef.current?.panHandlers ?? {};
34514
34648
  return /* @__PURE__ */ jsx25(
34515
- View21,
34649
+ Reanimated.View,
34516
34650
  {
34517
- pointerEvents: "box-none",
34651
+ pointerEvents: chromeVisible ? "box-none" : "none",
34652
+ accessibilityElementsHidden: !chromeVisible,
34653
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
34518
34654
  style: [
34519
34655
  styles21.frame,
34656
+ chromeMotion,
34520
34657
  resolvePageScrubberOverlayStyle(),
34521
34658
  {
34522
34659
  top: offsets.progress,
@@ -35253,6 +35390,7 @@ function ReadingShell({
35253
35390
  /* @__PURE__ */ jsx28(
35254
35391
  Topbar_default,
35255
35392
  {
35393
+ documentType,
35256
35394
  engine,
35257
35395
  title,
35258
35396
  onOpenSettings: () => openDestination("display"),
@@ -35263,6 +35401,7 @@ function ReadingShell({
35263
35401
  /* @__PURE__ */ jsx28(View23, { style: styles24.viewerStage, children: /* @__PURE__ */ jsx28(
35264
35402
  Viewer_default,
35265
35403
  {
35404
+ documentType,
35266
35405
  engine,
35267
35406
  ...viewerProps,
35268
35407
  pageScrubActive
@@ -35387,6 +35526,7 @@ function ReadingShell({
35387
35526
  /* @__PURE__ */ jsx28(
35388
35527
  PageJumpModal,
35389
35528
  {
35529
+ documentType,
35390
35530
  visible: pageJumpOpen,
35391
35531
  currentPage,
35392
35532
  pageCount,