@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.js CHANGED
@@ -20517,6 +20517,42 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20517
20517
  <!-- @papyrus-comic-runtime:end -->
20518
20518
  <script>
20519
20519
  (function () {
20520
+ /* @papyrus-epub-reader:start */
20521
+ (function(root){
20522
+ function mode(value){return value==='chapter-scroll'?'chapter-scroll':'paged';}
20523
+ function validCfi(value){return typeof value==='string' && value.length<=4096 && /^epubcfi\\([^\\n<>]+\\)$/.test(value);}
20524
+ function options(value){return {manager:'default',flow:mode(value)==='paged'?'paginated':'scrolled-doc',spread:'none',width:'100%',height:'100%',allowScriptedContent:false};}
20525
+ function gesture(start,end,state){
20526
+ if(!start || !end || state.selected || state.interactive || state.multitouch)return null;
20527
+ var dx=end.x-start.x,dy=end.y-start.y,elapsed=end.time-start.time;
20528
+ 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';
20529
+ if(elapsed>=0 && elapsed<450 && Math.hypot(dx,dy)<=12)return 'tap';
20530
+ return null;
20531
+ }
20532
+ function location(raw,count,readingMode){
20533
+ var start=raw && raw.start;if(!start || !validCfi(start.cfi))return null;
20534
+ var displayed=start.displayed||{},chapter=Math.max(1,(Number(start.index)||0)+1);
20535
+ var visualPage=mode(readingMode)==='paged' && Number.isFinite(displayed.page)?displayed.page:null;
20536
+ var total=mode(readingMode)==='paged' && Number.isFinite(displayed.total)?displayed.total:null;
20537
+ var fraction=total?Math.max(0,(visualPage-1)/total):0;
20538
+ 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)};
20539
+ }
20540
+ function install(contents,config){
20541
+ var doc=contents.document,win=contents.window,start=null,blocked=false;
20542
+ 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;}
20543
+ function selected(){return Boolean(String(win.getSelection()||'').trim()) || config.blocked();}
20544
+ function interactive(target){return Boolean(target && target.closest && target.closest('a,button,input,textarea,select,[contenteditable="true"],[data-papyrus-overlay]'));}
20545
+ function begin(e){start=point(e);blocked=e.touches.length!==1 || selected() || interactive(e.target);}
20546
+ function move(e){if(e.touches.length!==1)blocked=true;}
20547
+ 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);}
20548
+ function cancel(){start=null;blocked=true;}
20549
+ doc.addEventListener('touchstart',begin,{passive:true});doc.addEventListener('touchmove',move,{passive:true});doc.addEventListener('touchend',end,{passive:true});doc.addEventListener('touchcancel',cancel,{passive:true});
20550
+ return function(){doc.removeEventListener('touchstart',begin);doc.removeEventListener('touchmove',move);doc.removeEventListener('touchend',end);doc.removeEventListener('touchcancel',cancel);};
20551
+ }
20552
+ root.PapyrusEpubReader={mode:mode,validCfi:validCfi,options:options,gesture:gesture,location:location,install:install};
20553
+ })(typeof window==='undefined'?globalThis:window);
20554
+
20555
+ /* @papyrus-epub-reader:end */
20520
20556
  /* @papyrus-epub-annotations:start */
20521
20557
  (function (root, factory) {
20522
20558
  if (typeof module === 'object' && module.exports) module.exports = factory();
@@ -20595,6 +20631,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20595
20631
  var color = /^#[0-9a-f]{6}$/i.test(annotation.color) ? annotation.color : '#FFC928';
20596
20632
  var style = annotation.markupStyle || annotation.type;
20597
20633
  var opacity = Number.isFinite(annotation.opacity) ? Math.max(0,Math.min(1,annotation.opacity)) : 0.35;
20634
+ if(style === 'highlight')opacity=Math.min(0.35,opacity);
20598
20635
  rects.forEach(function(rect) {
20599
20636
  var mark = doc.createElement('div');
20600
20637
  var bodyRect=doc.body.getBoundingClientRect();
@@ -20607,8 +20644,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20607
20644
  if (hasNote) {
20608
20645
  var last = rects[rects.length-1], button = doc.createElement('button');
20609
20646
  button.textContent = '\u25CF'; button.setAttribute('aria-label',options.labels().comment || '');
20610
- 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';
20611
- var key = Math.floor(last.top/44);
20647
+ var pageWidth=Math.max(44, options.pageWidth ? options.pageWidth() : win.innerWidth);
20648
+ var bodyRect=doc.body.getBoundingClientRect(), column=Math.max(0,Math.floor((last.left-bodyRect.left)/pageWidth));
20649
+ 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';
20650
+ var key = column+":"+Math.floor(last.top/44);
20612
20651
  var neighbors=noteGroups.get(key);
20613
20652
  if(!neighbors){neighbors={button:button,ids:[]};noteGroups.set(key,neighbors);group.appendChild(button);}
20614
20653
  neighbors.ids.push(annotation.id);
@@ -20629,10 +20668,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
20629
20668
  doc.addEventListener('click',tapMarkup);
20630
20669
  var observer = typeof win.ResizeObserver === 'function' ? new win.ResizeObserver(schedule) : null;
20631
20670
  if (observer) observer.observe(doc.body);
20632
- win.addEventListener('resize',schedule); doc.addEventListener('load',schedule,true);
20671
+ win.addEventListener('resize',schedule);win.addEventListener('scroll',schedule); doc.addEventListener('load',schedule,true);
20633
20672
  if (doc.fonts && doc.fonts.ready) doc.fonts.ready.then(schedule);
20634
20673
  schedule();
20635
- 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();}};
20674
+ 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();}};
20636
20675
  }
20637
20676
  return {validAnchor:validAnchor,recoverRange:recoverRange,resolveRange:resolveRange,selection:selection,install:install};
20638
20677
  });
@@ -21713,26 +21752,55 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21713
21752
  pageCount,
21714
21753
  });
21715
21754
 
21755
+ if (book.locations?.generate) {
21756
+ const activeBook=book;
21757
+ activeBook.locations.generate(150).then(() => {
21758
+ if (isCurrentLoad() && activeBook===book && epubLocation) {
21759
+ epubLocation.progress=activeBook.locations.percentageFromCfi(epubLocation.cfi);
21760
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21761
+ }
21762
+ }).catch(() => {});
21763
+ }
21764
+ return renderEpubRendition(loadId,generation,null);
21765
+ };
21766
+
21767
+ const renderEpubRendition = async (loadId,generation,target) => {
21768
+ const diagnosticPayload={loadId};
21769
+ const isCurrentLoad=()=>generation===epubLoadGeneration;
21770
+ if(epubInteractionCleanup)epubInteractionCleanup();
21771
+ if(rendition)rendition.destroy();
21716
21772
  clearViewer();
21717
- rendition = book.renderTo(viewer, {
21718
- manager: 'continuous',
21719
- allowScriptedContent: false,
21720
- width: '100%',
21721
- height: '100%',
21722
- flow: 'scrolled-continuous',
21723
- spread: 'none',
21724
- });
21773
+ rendition = book.renderTo(viewer, window.PapyrusEpubReader.options(epubViewMode === 'single' ? 'paged' : 'chapter-scroll'));
21725
21774
  sendEpubDiagnostic('epub.rendition.created', diagnosticPayload);
21726
21775
 
21727
21776
  if (rendition && rendition.hooks && rendition.hooks.content) {
21728
21777
  const session = documentSessionId;
21729
21778
  const activeRendition = rendition;
21730
21779
  rendition.hooks.content.register((contents) => {
21780
+ const removeGestureListeners = window.PapyrusEpubReader.install(contents, {
21781
+ mode: () => epubViewMode === 'single' ? 'paged' : 'chapter-scroll',
21782
+ rtl: () => book.package?.metadata?.direction === 'rtl' || book.spine?.direction === 'rtl',
21783
+ blocked: () => Boolean(nativeMenuSelection && String(nativeMenuSelection.contents?.window?.getSelection() || '').trim()),
21784
+ annotationHit: point => epubAnnotationRenderers.get(contents)?.hit(point.x,point.y),
21785
+ current: () => session === documentSessionId && activeRendition === rendition,
21786
+ tap: () => sendEvent('EPUB_CONTENT_TAP',{documentSessionId:session}),
21787
+ turn: direction => {
21788
+ epubNavigationQueue = epubNavigationQueue.catch(()=>{}).then(() => {
21789
+ if(session !== documentSessionId || activeRendition !== rendition)return;
21790
+ return direction<0?activeRendition.prev():activeRendition.next();
21791
+ });
21792
+ epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR',{message:String(error)}));
21793
+ },
21794
+ });
21795
+ const gestureCleanup = () => {removeGestureListeners();epubSelectionCleanups.delete(gestureCleanup);};
21796
+ epubSelectionCleanups.add(gestureCleanup);
21797
+ contents.__papyrusGestureCleanup=gestureCleanup;
21731
21798
  const href = spineItems[contents.sectionIndex]?.href;
21732
21799
  if (href && window.PapyrusEpubAnnotations) {
21733
21800
  const renderer = window.PapyrusEpubAnnotations.install(contents, {
21734
21801
  href, get documentId() { return annotationDocumentId; },
21735
21802
  isCurrent: () => session === documentSessionId && activeRendition === rendition,
21803
+ pageWidth: () => activeRendition.layout?.width || viewer.clientWidth,
21736
21804
  annotations: () => epubAnnotations, labels: () => annotationLabels,
21737
21805
  onTap: (id, ids) => sendEvent("EPUB_ANNOTATION_TAP", {documentSessionId: session, id, ids}),
21738
21806
  });
@@ -21751,8 +21819,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21751
21819
  typeof selectionWindow.getSelection === 'function'
21752
21820
  ) {
21753
21821
  let selectionTimer = null;
21754
- let lastSelectionKey = '';
21755
- let lastSelectionAt = 0;
21822
+
21756
21823
  const reportSelection = () => {
21757
21824
  selectionTimer = null;
21758
21825
  if (session !== documentSessionId || activeRendition !== rendition) return;
@@ -21767,11 +21834,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21767
21834
  try { cfi = contents.cfiFromRange(range); } catch (_) { return; }
21768
21835
  const anchor = window.PapyrusEpubAnnotations?.selection(contents, cfi, href, annotationDocumentId);
21769
21836
  if (!anchor) return;
21770
- const key = anchor.cfiRange + ':' + anchor.quote;
21771
- const now = Date.now();
21772
- if (key === lastSelectionKey && now - lastSelectionAt < 750) return;
21773
- lastSelectionKey = key;
21774
- lastSelectionAt = now;
21837
+ if (nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21775
21838
  const payload = {documentSessionId: session, text: anchor.quote,
21776
21839
  pageIndex: contents.sectionIndex + 1, anchor};
21777
21840
  nativeMenuSelection = {contents, payload};
@@ -21786,6 +21849,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21786
21849
  // The content document still emits selectionchange, so resolve its
21787
21850
  // live Range to a CFI before the native menu action can fire.
21788
21851
  if (text) reportSelection();
21852
+ else if (nativeMenuSelection?.contents === contents) nativeMenuSelection = null;
21789
21853
  };
21790
21854
  selectionDocument.addEventListener('selectionchange', handleSelectionChange);
21791
21855
  const selectionCleanup = () => {
@@ -21808,6 +21872,7 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21808
21872
  typeof rendition.hooks.unloaded.register === 'function'
21809
21873
  ) {
21810
21874
  rendition.hooks.unloaded.register((view) => {
21875
+ view?.contents?.__papyrusGestureCleanup?.();
21811
21876
  const cleanup = view && view.contents && view.contents.__papyrusSelectionCleanup;
21812
21877
  if (typeof cleanup === 'function') cleanup();
21813
21878
  const renderer = epubAnnotationRenderers.get(view?.contents);
@@ -21823,13 +21888,13 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21823
21888
  if (selectionSession !== documentSessionId || selectionRendition !== rendition) return;
21824
21889
  const href = spineItems[contents.sectionIndex]?.href;
21825
21890
  const anchor = href && window.PapyrusEpubAnnotations?.selection(contents,cfiRange,href,annotationDocumentId);
21826
- if (!anchor) return;
21891
+ if (!anchor || nativeMenuSelection?.payload?.anchor?.cfiRange === anchor.cfiRange && nativeMenuSelection?.payload?.anchor?.quote === anchor.quote) return;
21827
21892
  epubScrollDiagnostics && epubScrollDiagnostics.setSelectionActive(true);
21828
21893
  const payload = {documentSessionId: selectionSession, text: anchor.quote, pageIndex: contents.sectionIndex+1, anchor};
21829
21894
  nativeMenuSelection = {contents, payload};
21830
21895
  sendEvent('EPUB_TEXT_SELECTED', payload);
21831
21896
  });
21832
- ['rendered','resized','layout'].forEach(name => rendition.on(name, () => {
21897
+ ['rendered','resized','layout','relocated'].forEach(name => rendition.on(name, () => {
21833
21898
  if (selectionSession === documentSessionId && selectionRendition === rendition) epubAnnotationRenderers.forEach(renderer => renderer.schedule());
21834
21899
  }));
21835
21900
  rendition.on('relocated', (location) => {
@@ -21839,6 +21904,11 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21839
21904
  if (index < 0 && start && start.href) index = getSpineIndexByHref(start.href);
21840
21905
  if (index < 0 || index >= spineItems.length) return;
21841
21906
  epubScrollDiagnostics && epubScrollDiagnostics.relocated(location);
21907
+ epubLocation=window.PapyrusEpubReader.location(location,spineItems.length,epubViewMode==='single'?'paged':'chapter-scroll');
21908
+ if(epubLocation){
21909
+ if(book.locations?.length?.()>0)epubLocation.progress=book.locations.percentageFromCfi(epubLocation.cfi);
21910
+ sendEvent('EPUB_LOCATION',{documentSessionId,location:epubLocation});
21911
+ }
21842
21912
  const nextPage = index + 1;
21843
21913
  if (nextPage === currentPage) return;
21844
21914
  currentPage = nextPage;
@@ -21846,9 +21916,10 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21846
21916
  });
21847
21917
  }
21848
21918
 
21919
+ applyEpubZoom();
21849
21920
  sendEpubDiagnostic('epub.display.start', diagnosticPayload);
21850
21921
  await withEpubStageTimeout(
21851
- displayEpubPage(0),
21922
+ rendition.display(target || spineItems[0]?.href),
21852
21923
  'rendition.display',
21853
21924
  diagnosticPayload,
21854
21925
  );
@@ -21860,7 +21931,6 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21860
21931
  typeof rendition.manager.on === 'function' &&
21861
21932
  typeof rendition.on === 'function'
21862
21933
  ) {
21863
- let touchStart = null;
21864
21934
  let lastScrollOffset = -1;
21865
21935
  const manager = rendition.manager;
21866
21936
  epubScrollDiagnostics = createEpubScrollDiagnostics(manager);
@@ -21935,57 +22005,19 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21935
22005
  return result;
21936
22006
  };
21937
22007
  }
21938
- const getTouchPoint = (event) => {
21939
- const touch =
21940
- (event && event.changedTouches && event.changedTouches[0]) ||
21941
- (event && event.touches && event.touches[0]);
21942
- if (!touch) return null;
21943
- const x = Number(touch.screenX ?? touch.clientX);
21944
- const y = Number(touch.screenY ?? touch.clientY);
21945
- return Number.isFinite(x) && Number.isFinite(y) ? { x, y } : null;
21946
- };
21947
- const handleScroll = (event) => {
22008
+ const handleScroll = event => {
21948
22009
  const offsetY = Math.max(0, Number(event && event.top) || 0);
21949
22010
  epubScrollDiagnostics && epubScrollDiagnostics.scroll(event);
21950
- if (Math.abs(offsetY - lastScrollOffset) < 1) return;
21951
- lastScrollOffset = offsetY;
21952
- sendEvent('VIEWER_SCROLL', { offsetY });
21953
- };
21954
- const handleTouchStart = (event) => {
21955
- touchStart = event?.touches?.length > 1 ? null : getTouchPoint(event);
21956
- epubScrollDiagnostics && epubScrollDiagnostics.touchStart(event);
22011
+ if (Math.abs(offsetY-lastScrollOffset)<1) return;
22012
+ lastScrollOffset=offsetY;
22013
+ sendEvent('VIEWER_SCROLL',{offsetY});
21957
22014
  };
21958
- const handleTouchMove = (event) => {
21959
- if (event?.touches?.length > 1) touchStart = null;
21960
- epubScrollDiagnostics && epubScrollDiagnostics.touchMove(event);
21961
- };
21962
- const handleTouchEnd = (event) => {
21963
- const end = getTouchPoint(event);
21964
- const start = touchStart;
21965
- touchStart = null;
21966
- const selectedText = event?.target?.ownerDocument?.defaultView?.getSelection?.()?.toString().trim() || '';
21967
- if (!selectedText && start && end && epubViewMode === 'single' && Math.abs(end.x-start.x) >= 48 && Math.abs(end.x-start.x) > Math.abs(end.y-start.y)*1.5) {
21968
- const active = rendition;
21969
- const interactionSession = documentSessionId;
21970
- epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
21971
- if (active !== rendition || interactionSession !== documentSessionId) return;
21972
- return end.x < start.x ? active.next() : active.prev();
21973
- });
21974
- epubNavigationQueue.catch(error => sendEvent('EPUB_NAVIGATION_ERROR', {message:String(error)}));
21975
- } else if (!selectedText && start && end && Math.hypot(end.x - start.x, end.y - start.y) <= 12) {
21976
- sendEvent('VIEWER_TAP', {});
21977
- }
21978
- epubScrollDiagnostics && epubScrollDiagnostics.touchEnd(event);
21979
- };
21980
-
21981
22015
  manager.on('scroll', handleScroll);
21982
22016
  const handleScrolled = (event) => {
21983
22017
  epubScrollDiagnostics && epubScrollDiagnostics.settled(event);
21984
22018
  };
21985
22019
  manager.on('scrolled', handleScrolled);
21986
- rendition.on('touchstart', handleTouchStart);
21987
- rendition.on('touchmove', handleTouchMove);
21988
- rendition.on('touchend', handleTouchEnd);
22020
+
21989
22021
  epubInteractionCleanup = () => {
21990
22022
  epubSelectionCleanups.forEach((cleanup) => cleanup());
21991
22023
  epubSelectionCleanups.clear();
@@ -21994,16 +22026,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
21994
22026
  if (originalEnqueue) queue.enqueue = originalEnqueue;
21995
22027
  if (typeof manager.off === 'function') manager.off('scroll', handleScroll);
21996
22028
  if (typeof manager.off === 'function') manager.off('scrolled', handleScrolled);
21997
- if (typeof rendition.off === 'function') {
21998
- rendition.off('touchstart', handleTouchStart);
21999
- rendition.off('touchmove', handleTouchMove);
22000
- rendition.off('touchend', handleTouchEnd);
22001
- }
22002
22029
  epubScrollDiagnostics = null;
22003
22030
  };
22004
22031
  }
22005
- applyEpubZoom();
22006
-
22007
22032
  const outline = await withEpubStageTimeout(
22008
22033
  buildOutline(),
22009
22034
  'outline',
@@ -22141,7 +22166,8 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22141
22166
  };
22142
22167
 
22143
22168
  let nativeMenuSelection = null;
22144
- let epubViewMode = "continuous";
22169
+ let epubViewMode = "single";
22170
+ let epubLocation = null;
22145
22171
 
22146
22172
  const handleCommand = async (message) => {
22147
22173
  const { id, kind, payload } = message;
@@ -22154,7 +22180,9 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22154
22180
  epubAnnotations = [];
22155
22181
  annotationDocumentId = undefined;
22156
22182
  zoom = 1.0;
22157
- epubViewMode = "continuous";
22183
+ epubViewMode = payload.epubMode === "chapter-scroll" ? "continuous" : "single";
22184
+ epubLocation = null;
22185
+ nativeMenuSelection = null;
22158
22186
  epubNavigationRequest += 1;
22159
22187
  epubNavigationQueue = Promise.resolve();
22160
22188
 
@@ -22268,25 +22296,40 @@ https://github.com/nodeca/pako/blob/main/LICENSE
22268
22296
 
22269
22297
  if (kind === 'set-epub-view-mode') {
22270
22298
  if (currentType !== 'epub' || payload.documentSessionId !== documentSessionId) throw new Error('Stale EPUB layout session');
22271
- epubViewMode = payload.viewMode === 'single' ? 'single' : 'continuous';
22272
- const active = rendition;
22273
- epubNavigationQueue = epubNavigationQueue.catch(() => {}).then(() => {
22274
- if (active !== rendition || payload.documentSessionId !== documentSessionId) return;
22275
- const flow = epubViewMode === 'single' ? 'paginated' : 'scrolled-continuous';
22276
- if (active.settings.flow === flow) return;
22277
- active.flow(flow);
22278
- return active.q.enqueue(() => Promise.resolve());
22279
- });
22280
- await epubNavigationQueue;
22281
- sendResponse(id,true,null); return;
22299
+ const next=payload.epubMode ? (payload.epubMode==='paged'?'single':'continuous') : (payload.viewMode==='single'?'single':'continuous');
22300
+ {
22301
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22302
+ if(payload.documentSessionId!==documentSessionId || next===epubViewMode)return;
22303
+ const target=epubLocation?.cfi;
22304
+ epubViewMode=next;
22305
+ await renderEpubRendition('layout',epubLoadGeneration,target);
22306
+ });
22307
+ await epubNavigationQueue;
22308
+ }
22309
+ sendResponse(id,true,null);return;
22310
+ }
22311
+ if(kind === 'epub-go-to-location'){
22312
+ if(currentType!=='epub' || payload.documentSessionId!==documentSessionId || !window.PapyrusEpubReader.validCfi(payload.cfi))throw new Error('Invalid EPUB location');
22313
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(()=>payload.documentSessionId===documentSessionId?rendition.display(payload.cfi):undefined);
22314
+ await epubNavigationQueue;sendResponse(id,true,null);return;
22282
22315
  }
22283
22316
 
22284
22317
  if (kind === 'set-zoom') {
22285
- zoom = Math.max(0.5, Math.min(4.0, payload.zoom || 1.0));
22286
- applyZoom();
22287
- sendState();
22288
- sendResponse(id, true, { zoom });
22289
- return;
22318
+ const requestedZoom=Math.max(0.5,Math.min(4.0,payload.zoom || 1.0));
22319
+ if(currentType === 'epub') {
22320
+ const session=documentSessionId;
22321
+ epubNavigationQueue=epubNavigationQueue.catch(()=>{}).then(async()=>{
22322
+ if(session!==documentSessionId)return;
22323
+ const active=rendition;
22324
+ const cfi=epubLocation?.cfi;
22325
+ zoom=requestedZoom;applyEpubZoom();
22326
+ // Let the content CSS update before redisplaying the logical anchor.
22327
+ await new Promise(resolve=>(window.requestAnimationFrame || (callback=>setTimeout(callback,0)))(resolve));
22328
+ if(cfi && active===rendition && session===documentSessionId)await active.display(cfi);
22329
+ });
22330
+ await epubNavigationQueue;
22331
+ } else {zoom=requestedZoom;applyZoom();}
22332
+ sendState();sendResponse(id,true,{zoom});return;
22290
22333
  }
22291
22334
 
22292
22335
  if (kind === 'set-rotation') {
@@ -23449,6 +23492,7 @@ var IconToolStrikeout = ({
23449
23492
  ),
23450
23493
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Rect, { x: "10.9", y: "17.1", width: "14.2", height: "2.4", rx: "1.2", fill: color })
23451
23494
  ] });
23495
+ var IconStrikeout = ({ size = 22, color = defaultColor, strokeWidth = 1.8 }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.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" }) });
23452
23496
  var IconCopy = ({
23453
23497
  size = 20,
23454
23498
  color = defaultColor,
@@ -23513,6 +23557,39 @@ var IconToolNote = ({
23513
23557
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Line, { x1: "15", y1: "14.8", x2: "21.6", y2: "14.8", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" }),
23514
23558
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Line, { x1: "15", y1: "18.2", x2: "19.2", y2: "18.2", stroke: color, strokeWidth: "1.8", strokeLinecap: "round" })
23515
23559
  ] });
23560
+ var IconHighlight = ({
23561
+ size = 24,
23562
+ color = "#fbbf24"
23563
+ }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: [
23564
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
23565
+ import_react_native_svg.Path,
23566
+ {
23567
+ d: "M4 15h16v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3Z",
23568
+ fill: color,
23569
+ opacity: "0.85"
23570
+ }
23571
+ ),
23572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
23573
+ import_react_native_svg.Path,
23574
+ {
23575
+ d: "M6 5h12v10H6V5Z",
23576
+ stroke: color,
23577
+ strokeWidth: "2",
23578
+ strokeLinecap: "round",
23579
+ strokeLinejoin: "round",
23580
+ fill: "none"
23581
+ }
23582
+ ),
23583
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
23584
+ import_react_native_svg.Path,
23585
+ {
23586
+ d: "M8 8h8M8 11h5",
23587
+ stroke: color,
23588
+ strokeWidth: "2",
23589
+ strokeLinecap: "round"
23590
+ }
23591
+ )
23592
+ ] });
23516
23593
  var IconUnderline = ({
23517
23594
  size = 24,
23518
23595
  color = "#60a5fa",
@@ -25941,8 +26018,38 @@ var styles = import_react_native.StyleSheet.create({
25941
26018
  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;
25942
26019
  var PageRenderer_default = (0, import_react2.memo)(PageRenderer, arePageRendererPropsEqual);
25943
26020
 
26021
+ // components/PapyrusSafeArea.tsx
26022
+ var import_react3 = __toESM(require("react"));
26023
+ var import_react_native_safe_area_context = require("react-native-safe-area-context");
26024
+ var import_jsx_runtime4 = require("react/jsx-runtime");
26025
+ var papyrusSafeAreaContext = import_react_native_safe_area_context.SafeAreaInsetsContext;
26026
+ var ZERO_SAFE_AREA_INSETS = {
26027
+ top: 0,
26028
+ bottom: 0,
26029
+ left: 0,
26030
+ right: 0
26031
+ };
26032
+ var usePapyrusSafeAreaInsets = () => (0, import_react3.useContext)(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
26033
+ function PapyrusSafeAreaBoundary({
26034
+ children
26035
+ }) {
26036
+ const insets = (0, import_react3.useContext)(papyrusSafeAreaContext);
26037
+ if (insets) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
26038
+ return import_react3.default.createElement(import_react_native_safe_area_context.SafeAreaProvider, null, children);
26039
+ }
26040
+
26041
+ // components/epubReadingLocation.ts
26042
+ function parseEpubReadingLocation(raw) {
26043
+ if (!raw || typeof raw !== "object") return null;
26044
+ const p = raw;
26045
+ 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;
26046
+ if (p.mode === "chapter-scroll") return p.visualPage === null && p.visualPageCount === null ? p : null;
26047
+ if (p.mode !== "paged" || !Number.isSafeInteger(p.visualPage) || (p.visualPage ?? 0) < 1 || !Number.isSafeInteger(p.visualPageCount) || (p.visualPageCount ?? 0) < (p.visualPage ?? 0)) return null;
26048
+ return p;
26049
+ }
26050
+
25944
26051
  // components/WebViewViewer.tsx
25945
- var import_react3 = require("react");
26052
+ var import_react4 = require("react");
25946
26053
  var import_react_native2 = require("react-native");
25947
26054
  var import_clipboard3 = __toESM(require("@react-native-clipboard/clipboard"));
25948
26055
  var import_react_native_webview = __toESM(require("react-native-webview"));
@@ -26010,7 +26117,7 @@ function parseEpubAnnotationEvent(raw, session, documentId) {
26010
26117
  }
26011
26118
 
26012
26119
  // components/WebViewViewer.tsx
26013
- var import_jsx_runtime4 = require("react/jsx-runtime");
26120
+ var import_jsx_runtime5 = require("react/jsx-runtime");
26014
26121
  var runtimeAsset = require_runtime();
26015
26122
  var resolveRuntimeSource = (asset) => {
26016
26123
  if (typeof asset === "string") {
@@ -26030,6 +26137,7 @@ var resolveRuntimeSource = (asset) => {
26030
26137
  };
26031
26138
  var WebViewViewer = ({
26032
26139
  engine,
26140
+ documentType,
26033
26141
  documentId,
26034
26142
  onDefineSelection,
26035
26143
  defineSelectionMode,
@@ -26037,19 +26145,20 @@ var WebViewViewer = ({
26037
26145
  onScrollOffset,
26038
26146
  onTap
26039
26147
  }) => {
26040
- const webViewRef = (0, import_react3.useRef)(null);
26041
- const { pageTheme, viewMode, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = (0, import_core4.useViewerStore)();
26042
- const [selection, setSelection] = (0, import_react3.useState)(null);
26148
+ const webViewRef = (0, import_react4.useRef)(null);
26149
+ const insets = usePapyrusSafeAreaInsets();
26150
+ const { pageTheme, epubReadingMode, setDocumentState, annotations, isLoaded, locale, annotationColor, annotationOpacity, addAnnotation, beginAnnotationDraft, setSelectedAnnotation } = (0, import_core4.useViewerStore)();
26151
+ const [selection, setSelection] = (0, import_react4.useState)(null);
26043
26152
  const t = getStrings(locale);
26044
26153
  const bridgeEngine = engine;
26045
- const runtimeSource = (0, import_react3.useMemo)(
26154
+ const runtimeSource = (0, import_react4.useMemo)(
26046
26155
  () => resolveRuntimeSource(
26047
26156
  bridgeEngine.getWebViewRuntimeSource?.() ?? runtimeAsset
26048
26157
  ),
26049
26158
  [bridgeEngine]
26050
26159
  );
26051
- const [runtimeHtml, setRuntimeHtml] = (0, import_react3.useState)(null);
26052
- (0, import_react3.useEffect)(() => {
26160
+ const [runtimeHtml, setRuntimeHtml] = (0, import_react4.useState)(null);
26161
+ (0, import_react4.useEffect)(() => {
26053
26162
  let active = true;
26054
26163
  if ("html" in runtimeSource) {
26055
26164
  setRuntimeHtml(runtimeSource.html);
@@ -26070,7 +26179,7 @@ var WebViewViewer = ({
26070
26179
  active = false;
26071
26180
  };
26072
26181
  }, [runtimeSource]);
26073
- const webViewSource = (0, import_react3.useMemo)(() => {
26182
+ const webViewSource = (0, import_react4.useMemo)(() => {
26074
26183
  if (runtimeHtml !== null) {
26075
26184
  return {
26076
26185
  html: runtimeHtml,
@@ -26081,13 +26190,13 @@ var WebViewViewer = ({
26081
26190
  return runtimeSource;
26082
26191
  }, [runtimeHtml, runtimeSource]);
26083
26192
  const runtimeConfig = bridgeEngine.getWebViewRuntimeConfig?.();
26084
- const runtimeConfigScript = (0, import_react3.useMemo)(() => {
26193
+ const runtimeConfigScript = (0, import_react4.useMemo)(() => {
26085
26194
  if (!runtimeConfig) return void 0;
26086
26195
  return `window.__PAPYRUS_RUNTIME_CONFIG__=${JSON.stringify(
26087
26196
  runtimeConfig
26088
26197
  )};true;`;
26089
26198
  }, [runtimeConfig]);
26090
- (0, import_react3.useEffect)(() => {
26199
+ (0, import_react4.useEffect)(() => {
26091
26200
  bridgeEngine.attachWebView?.({
26092
26201
  postMessage: (message) => {
26093
26202
  if (__DEV__) {
@@ -26101,10 +26210,10 @@ var WebViewViewer = ({
26101
26210
  bridgeEngine.detachWebView?.();
26102
26211
  };
26103
26212
  }, [bridgeEngine]);
26104
- (0, import_react3.useEffect)(() => {
26213
+ (0, import_react4.useEffect)(() => {
26105
26214
  setSelection(null);
26106
26215
  }, [engine, documentId]);
26107
- (0, import_react3.useEffect)(() => {
26216
+ (0, import_react4.useEffect)(() => {
26108
26217
  if (!isLoaded) return;
26109
26218
  let active = true;
26110
26219
  void bridgeEngine.syncEpubAnnotations?.(annotations, documentId, { comment: t.annotationNote }).catch(() => {
@@ -26119,10 +26228,10 @@ var WebViewViewer = ({
26119
26228
  (note !== void 0 ? beginAnnotationDraft : addAnnotation)((0, import_core4.createContextualAnnotation)({ id: `annotation-${Date.now()}-${Math.random().toString(36).slice(2)}`, anchor: selected.anchor, pageIndex: selected.pageIndex, style, color: annotationColor, opacity: annotationOpacity, note }));
26120
26229
  setSelection(null);
26121
26230
  };
26122
- (0, import_react3.useEffect)(() => {
26231
+ (0, import_react4.useEffect)(() => {
26123
26232
  if (!isLoaded) return;
26124
- webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { viewMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26125
- }, [isLoaded, viewMode, bridgeEngine]);
26233
+ webViewRef.current?.postMessage(JSON.stringify({ id: "epub-layout", kind: "set-epub-view-mode", payload: { epubMode: epubReadingMode, documentSessionId: bridgeEngine.getWebViewDocumentSessionId?.() } }));
26234
+ }, [isLoaded, epubReadingMode, bridgeEngine]);
26126
26235
  const sendSelectionCommand = (key) => {
26127
26236
  webViewRef.current?.postMessage(JSON.stringify({
26128
26237
  type: "epub-selection-action",
@@ -26146,6 +26255,11 @@ var WebViewViewer = ({
26146
26255
  let annotationRaw = raw;
26147
26256
  try {
26148
26257
  const message = JSON.parse(raw);
26258
+ if (message.type === "event" && message.name === "EPUB_LOCATION" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) {
26259
+ const location = parseEpubReadingLocation(message.payload.location);
26260
+ if (location) setDocumentState({ epubLocation: location });
26261
+ }
26262
+ if (message.type === "event" && message.name === "EPUB_CONTENT_TAP" && message.payload?.documentSessionId === bridgeEngine.getWebViewDocumentSessionId?.()) onTap?.();
26149
26263
  if (message.type === "event" && message.name === "EPUB_SELECTION_ACTION") {
26150
26264
  action = message.payload?.action;
26151
26265
  annotationRaw = JSON.stringify({ ...message, name: "EPUB_TEXT_SELECTED" });
@@ -26209,7 +26323,7 @@ var WebViewViewer = ({
26209
26323
  console.warn("[Papyrus WebView] error", event.nativeEvent);
26210
26324
  }
26211
26325
  };
26212
- const themeOverlayStyle = (0, import_react3.useMemo)(() => {
26326
+ const themeOverlayStyle = (0, import_react4.useMemo)(() => {
26213
26327
  switch (pageTheme) {
26214
26328
  case "sepia":
26215
26329
  return styles2.themeSepia;
@@ -26221,7 +26335,7 @@ var WebViewViewer = ({
26221
26335
  return styles2.themeNone;
26222
26336
  }
26223
26337
  }, [pageTheme]);
26224
- const allowingReadAccessToURL = (0, import_react3.useMemo)(() => {
26338
+ const allowingReadAccessToURL = (0, import_react4.useMemo)(() => {
26225
26339
  if (!runtimeSource || typeof runtimeSource !== "object") return void 0;
26226
26340
  if ("uri" in runtimeSource && runtimeSource.uri) {
26227
26341
  return runtimeSource.uri;
@@ -26234,8 +26348,8 @@ var WebViewViewer = ({
26234
26348
  maxWidth: resolvedMaxPageWidth,
26235
26349
  alignSelf: "center"
26236
26350
  } : void 0;
26237
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native2.View, { style: styles2.container, children: [
26238
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
26351
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native2.View, { style: [styles2.container, documentType === "epub" && { paddingTop: insets.top, paddingBottom: insets.bottom }], children: [
26352
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
26239
26353
  import_react_native_webview.default,
26240
26354
  {
26241
26355
  ref: webViewRef,
@@ -26259,7 +26373,7 @@ var WebViewViewer = ({
26259
26373
  style: [styles2.webview, cappedWebViewStyle]
26260
26374
  }
26261
26375
  ),
26262
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
26376
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
26263
26377
  import_react_native2.View,
26264
26378
  {
26265
26379
  pointerEvents: "none",
@@ -26361,22 +26475,22 @@ function getNearbyPdfNotes(annotations, id) {
26361
26475
  // components/PdfNoteChooser.tsx
26362
26476
  var import_react_native3 = require("react-native");
26363
26477
  var import_core5 = require("@papyrus-sdk/core");
26364
- var import_jsx_runtime5 = require("react/jsx-runtime");
26478
+ var import_jsx_runtime6 = require("react/jsx-runtime");
26365
26479
  function PdfNoteChooser({ notes, title, cancel, onSelect, onClose }) {
26366
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.Modal, { visible: notes.length > 1, transparent: true, animationType: "none", onRequestClose: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.View, { style: styles3.backdrop, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.View, { style: styles3.sheet, accessibilityViewIsModal: true, children: [
26367
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.Text, { style: styles3.title, children: title }),
26368
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.Pressable, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native3.Text, { children: [
26480
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.Modal, { visible: notes.length > 1, transparent: true, animationType: "none", onRequestClose: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.View, { style: styles3.backdrop, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native3.View, { style: styles3.sheet, accessibilityViewIsModal: true, children: [
26481
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.Text, { style: styles3.title, children: title }),
26482
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.FlatList, { data: notes, keyExtractor: (a) => a.id, renderItem: ({ item, index }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.Pressable, { accessibilityRole: "button", style: styles3.row, onPress: () => onSelect(item.id), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native3.Text, { children: [
26369
26483
  index + 1,
26370
26484
  ". ",
26371
26485
  (0, import_core5.getAnnotationNote)(item) || (0, import_core5.getAnnotationQuote)(item)
26372
26486
  ] }) }) }),
26373
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.Pressable, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native3.Text, { children: cancel }) })
26487
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.Pressable, { accessibilityRole: "button", style: styles3.row, onPress: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.Text, { children: cancel }) })
26374
26488
  ] }) }) });
26375
26489
  }
26376
26490
  var styles3 = import_react_native3.StyleSheet.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 } });
26377
26491
 
26378
26492
  // components/DedicatedAndroidPdfViewer.tsx
26379
- var import_react4 = require("react");
26493
+ var import_react5 = require("react");
26380
26494
  var import_react_native4 = require("react-native");
26381
26495
  var import_core6 = require("@papyrus-sdk/core");
26382
26496
  var import_engine_native2 = require("@papyrus-sdk/engine-native");
@@ -26397,7 +26511,7 @@ var resolvePageTapChromeVisibility = ({
26397
26511
  };
26398
26512
 
26399
26513
  // components/DedicatedAndroidPdfViewer.tsx
26400
- var import_jsx_runtime6 = require("react/jsx-runtime");
26514
+ var import_jsx_runtime7 = require("react/jsx-runtime");
26401
26515
  var TEXT_MARKUP_TOOLS2 = /* @__PURE__ */ new Set(["highlight", "underline", "squiggly", "strikeout"]);
26402
26516
  var MOBILE_CHROME_HIDE_DELTA = 28;
26403
26517
  var MOBILE_CHROME_SHOW_DELTA = 22;
@@ -26426,7 +26540,7 @@ function DedicatedAndroidPdfViewer({
26426
26540
  const searchResults = (0, import_core6.useViewerStore)((state) => state.searchResults);
26427
26541
  const annotationNavigationRequest = (0, import_core6.useViewerStore)((state) => state.annotationNavigationRequest);
26428
26542
  const annotations = (0, import_core6.useViewerStore)((state) => state.annotations);
26429
- const [pendingNotes, setPendingNotes] = (0, import_react4.useState)([]);
26543
+ const [pendingNotes, setPendingNotes] = (0, import_react5.useState)([]);
26430
26544
  const handleAnnotationTap = (id) => {
26431
26545
  const nearby = getNearbyPdfNotes(annotations, id);
26432
26546
  if (nearby.length < 2) {
@@ -26454,30 +26568,30 @@ function DedicatedAndroidPdfViewer({
26454
26568
  maxWidth: resolvedMaxPageWidth,
26455
26569
  alignSelf: "center"
26456
26570
  } : void 0;
26457
- const [selection, setSelection] = (0, import_react4.useState)(null);
26458
- const selectionRef = (0, import_react4.useRef)(null);
26459
- const lastVisiblePagesKeyRef = (0, import_react4.useRef)("");
26460
- const lastScrollOffsetYRef = (0, import_react4.useRef)(0);
26461
- const scrollDownAccumRef = (0, import_react4.useRef)(0);
26462
- const scrollUpAccumRef = (0, import_react4.useRef)(0);
26463
- const pendingChromeShowTimeoutRef = (0, import_react4.useRef)(null);
26464
- const chromeVisibleRef = (0, import_react4.useRef)(true);
26465
- const lastZoomChangedAtRef = (0, import_react4.useRef)(null);
26466
- (0, import_react4.useEffect)(() => {
26571
+ const [selection, setSelection] = (0, import_react5.useState)(null);
26572
+ const selectionRef = (0, import_react5.useRef)(null);
26573
+ const lastVisiblePagesKeyRef = (0, import_react5.useRef)("");
26574
+ const lastScrollOffsetYRef = (0, import_react5.useRef)(0);
26575
+ const scrollDownAccumRef = (0, import_react5.useRef)(0);
26576
+ const scrollUpAccumRef = (0, import_react5.useRef)(0);
26577
+ const pendingChromeShowTimeoutRef = (0, import_react5.useRef)(null);
26578
+ const chromeVisibleRef = (0, import_react5.useRef)(true);
26579
+ const lastZoomChangedAtRef = (0, import_react5.useRef)(null);
26580
+ (0, import_react5.useEffect)(() => {
26467
26581
  chromeVisibleRef.current = mobileChromeVisible;
26468
26582
  }, [mobileChromeVisible]);
26469
- const clearPendingChromeShow = (0, import_react4.useCallback)(() => {
26583
+ const clearPendingChromeShow = (0, import_react5.useCallback)(() => {
26470
26584
  if (pendingChromeShowTimeoutRef.current) {
26471
26585
  clearTimeout(pendingChromeShowTimeoutRef.current);
26472
26586
  pendingChromeShowTimeoutRef.current = null;
26473
26587
  }
26474
26588
  }, []);
26475
- const setMobileChromeVisible = (0, import_react4.useCallback)((visible, reason) => {
26589
+ const setMobileChromeVisible = (0, import_react5.useCallback)((visible, reason) => {
26476
26590
  if (chromeVisibleRef.current === visible) return;
26477
26591
  chromeVisibleRef.current = visible;
26478
26592
  setDocumentState({ mobileChromeVisible: visible });
26479
26593
  }, [setDocumentState]);
26480
- const trackMobileChromeByOffset = (0, import_react4.useCallback)((offsetY, reasonPrefix) => {
26594
+ const trackMobileChromeByOffset = (0, import_react5.useCallback)((offsetY, reasonPrefix) => {
26481
26595
  const safeOffset = Math.max(0, offsetY);
26482
26596
  const delta = safeOffset - lastScrollOffsetYRef.current;
26483
26597
  lastScrollOffsetYRef.current = safeOffset;
@@ -26513,12 +26627,12 @@ function DedicatedAndroidPdfViewer({
26513
26627
  }
26514
26628
  }
26515
26629
  }, [clearPendingChromeShow, setMobileChromeVisible]);
26516
- (0, import_react4.useEffect)(() => {
26630
+ (0, import_react5.useEffect)(() => {
26517
26631
  return () => {
26518
26632
  clearPendingChromeShow();
26519
26633
  };
26520
26634
  }, [clearPendingChromeShow]);
26521
- const applySelection = (0, import_react4.useCallback)((type) => {
26635
+ const applySelection = (0, import_react5.useCallback)((type) => {
26522
26636
  const sel = selectionRef.current;
26523
26637
  if (!sel || !sel.rects || sel.rects.length === 0) return;
26524
26638
  const bounds = sel.rects.reduce((acc, r) => ({
@@ -26540,12 +26654,12 @@ function DedicatedAndroidPdfViewer({
26540
26654
  setSelection(null);
26541
26655
  selectionRef.current = null;
26542
26656
  }, [addAnnotation, beginAnnotationDraft, annotationColor, documentId]);
26543
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native4.View, { style: styles4.container, children: [
26544
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26657
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native4.View, { style: styles4.container, children: [
26658
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26545
26659
  setPendingNotes([]);
26546
26660
  setSelectedAnnotation(id);
26547
26661
  } }),
26548
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
26662
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
26549
26663
  import_engine_native2.PapyrusPdfDocumentView,
26550
26664
  {
26551
26665
  style: [styles4.viewer, cappedViewerStyle],
@@ -26659,7 +26773,7 @@ var styles4 = import_react_native4.StyleSheet.create({
26659
26773
  });
26660
26774
 
26661
26775
  // components/DedicatedIosPdfViewer.tsx
26662
- var import_react5 = require("react");
26776
+ var import_react6 = require("react");
26663
26777
  var import_react_native5 = require("react-native");
26664
26778
  var import_core7 = require("@papyrus-sdk/core");
26665
26779
  var import_engine_native3 = require("@papyrus-sdk/engine-native");
@@ -26756,7 +26870,7 @@ var resolveNativePdfVisiblePages = (pages) => (pages ?? []).flatMap((page) => {
26756
26870
  });
26757
26871
 
26758
26872
  // components/DedicatedIosPdfViewer.tsx
26759
- var import_jsx_runtime7 = require("react/jsx-runtime");
26873
+ var import_jsx_runtime8 = require("react/jsx-runtime");
26760
26874
  var MOBILE_CHROME_HIDE_DELTA2 = 28;
26761
26875
  var MOBILE_CHROME_SHOW_DELTA2 = 22;
26762
26876
  var MOBILE_CHROME_SHOW_DELAY_MS2 = 180;
@@ -26788,7 +26902,7 @@ function DedicatedIosPdfViewer({
26788
26902
  const inkStrokeWidth = (0, import_core7.useViewerStore)((state) => state.inkStrokeWidth);
26789
26903
  const annotationNavigationRequest = (0, import_core7.useViewerStore)((state) => state.annotationNavigationRequest);
26790
26904
  const annotations = (0, import_core7.useViewerStore)((state) => state.annotations);
26791
- const [pendingNotes, setPendingNotes] = (0, import_react5.useState)([]);
26905
+ const [pendingNotes, setPendingNotes] = (0, import_react6.useState)([]);
26792
26906
  const handleAnnotationTap = (id) => {
26793
26907
  const nearby = getNearbyPdfNotes(annotations, id);
26794
26908
  if (nearby.length < 2) {
@@ -26824,16 +26938,16 @@ function DedicatedIosPdfViewer({
26824
26938
  supportsNativeEditMenu
26825
26939
  );
26826
26940
  const resolvedMaxPageWidth = typeof maxPageWidth === "number" && Number.isFinite(maxPageWidth) && maxPageWidth > 0 ? maxPageWidth : void 0;
26827
- const chromeVisibleRef = (0, import_react5.useRef)(mobileChromeVisible);
26828
- const lastScrollOffsetYRef = (0, import_react5.useRef)(0);
26829
- const scrollDownAccumRef = (0, import_react5.useRef)(0);
26830
- const scrollUpAccumRef = (0, import_react5.useRef)(0);
26831
- const pendingChromeShowTimeoutRef = (0, import_react5.useRef)(null);
26832
- const lastZoomChangedAtRef = (0, import_react5.useRef)(null);
26833
- const lastVisiblePagesKeyRef = (0, import_react5.useRef)("");
26834
- const [selection, setSelection] = (0, import_react5.useState)(null);
26835
- const selectionRef = (0, import_react5.useRef)(null);
26836
- (0, import_react5.useEffect)(() => {
26941
+ const chromeVisibleRef = (0, import_react6.useRef)(mobileChromeVisible);
26942
+ const lastScrollOffsetYRef = (0, import_react6.useRef)(0);
26943
+ const scrollDownAccumRef = (0, import_react6.useRef)(0);
26944
+ const scrollUpAccumRef = (0, import_react6.useRef)(0);
26945
+ const pendingChromeShowTimeoutRef = (0, import_react6.useRef)(null);
26946
+ const lastZoomChangedAtRef = (0, import_react6.useRef)(null);
26947
+ const lastVisiblePagesKeyRef = (0, import_react6.useRef)("");
26948
+ const [selection, setSelection] = (0, import_react6.useState)(null);
26949
+ const selectionRef = (0, import_react6.useRef)(null);
26950
+ (0, import_react6.useEffect)(() => {
26837
26951
  const pickerActive = supportsNativeEditMenu && activeTool === "ink";
26838
26952
  setDocumentState({ nativeInkToolPickerActive: pickerActive });
26839
26953
  return () => {
@@ -26842,15 +26956,15 @@ function DedicatedIosPdfViewer({
26842
26956
  }
26843
26957
  };
26844
26958
  }, [activeTool, setDocumentState]);
26845
- (0, import_react5.useEffect)(() => {
26959
+ (0, import_react6.useEffect)(() => {
26846
26960
  chromeVisibleRef.current = mobileChromeVisible;
26847
26961
  }, [mobileChromeVisible]);
26848
- const clearPendingChromeShow = (0, import_react5.useCallback)(() => {
26962
+ const clearPendingChromeShow = (0, import_react6.useCallback)(() => {
26849
26963
  if (!pendingChromeShowTimeoutRef.current) return;
26850
26964
  clearTimeout(pendingChromeShowTimeoutRef.current);
26851
26965
  pendingChromeShowTimeoutRef.current = null;
26852
26966
  }, []);
26853
- const setMobileChromeVisible = (0, import_react5.useCallback)(
26967
+ const setMobileChromeVisible = (0, import_react6.useCallback)(
26854
26968
  (visible) => {
26855
26969
  if (chromeVisibleRef.current === visible) return;
26856
26970
  chromeVisibleRef.current = visible;
@@ -26858,14 +26972,14 @@ function DedicatedIosPdfViewer({
26858
26972
  },
26859
26973
  [setDocumentState]
26860
26974
  );
26861
- const updateSelection = (0, import_react5.useCallback)(
26975
+ const updateSelection = (0, import_react6.useCallback)(
26862
26976
  (nextSelection) => {
26863
26977
  selectionRef.current = nextSelection;
26864
26978
  setSelection(nextSelection);
26865
26979
  },
26866
26980
  []
26867
26981
  );
26868
- const handleTextSelectionChange = (0, import_react5.useCallback)(
26982
+ const handleTextSelectionChange = (0, import_react6.useCallback)(
26869
26983
  (event) => {
26870
26984
  const nextSelection = resolveNativePdfTextSelection(event.nativeEvent);
26871
26985
  updateSelection(nextSelection);
@@ -26878,7 +26992,7 @@ function DedicatedIosPdfViewer({
26878
26992
  },
26879
26993
  [onTextSelected, setSelectedAnnotation, updateSelection]
26880
26994
  );
26881
- const defineSelection = (0, import_react5.useCallback)(() => {
26995
+ const defineSelection = (0, import_react6.useCallback)(() => {
26882
26996
  const currentSelection = selectionRef.current;
26883
26997
  if (!currentSelection) return;
26884
26998
  onDefineSelection?.({
@@ -26887,7 +27001,7 @@ function DedicatedIosPdfViewer({
26887
27001
  });
26888
27002
  updateSelection(null);
26889
27003
  }, [onDefineSelection, updateSelection]);
26890
- const handleNativeDefineSelection = (0, import_react5.useCallback)(
27004
+ const handleNativeDefineSelection = (0, import_react6.useCallback)(
26891
27005
  (event) => {
26892
27006
  const text = event.nativeEvent?.text;
26893
27007
  const pageIndex = event.nativeEvent?.pageIndex;
@@ -26899,7 +27013,7 @@ function DedicatedIosPdfViewer({
26899
27013
  },
26900
27014
  [onDefineSelection, updateSelection]
26901
27015
  );
26902
- const handleInkToolPickerVisibilityChange = (0, import_react5.useCallback)(
27016
+ const handleInkToolPickerVisibilityChange = (0, import_react6.useCallback)(
26903
27017
  (event) => {
26904
27018
  handleNativeInkPickerVisibility(
26905
27019
  event.nativeEvent?.visible === true,
@@ -26908,7 +27022,7 @@ function DedicatedIosPdfViewer({
26908
27022
  },
26909
27023
  []
26910
27024
  );
26911
- const trackMobileChromeByOffset = (0, import_react5.useCallback)(
27025
+ const trackMobileChromeByOffset = (0, import_react6.useCallback)(
26912
27026
  (offsetY) => {
26913
27027
  if (pageCount <= 0) return;
26914
27028
  const safeOffset = Math.max(0, offsetY);
@@ -26944,11 +27058,11 @@ function DedicatedIosPdfViewer({
26944
27058
  },
26945
27059
  [clearPendingChromeShow, pageCount, setMobileChromeVisible]
26946
27060
  );
26947
- (0, import_react5.useEffect)(
27061
+ (0, import_react6.useEffect)(
26948
27062
  () => () => clearPendingChromeShow(),
26949
27063
  [clearPendingChromeShow]
26950
27064
  );
26951
- const handleVisiblePagesChange = (0, import_react5.useCallback)(
27065
+ const handleVisiblePagesChange = (0, import_react6.useCallback)(
26952
27066
  (event) => {
26953
27067
  const pages = resolveNativePdfVisiblePages(
26954
27068
  event.nativeEvent?.pages
@@ -26963,13 +27077,13 @@ function DedicatedIosPdfViewer({
26963
27077
  },
26964
27078
  [setDocumentState]
26965
27079
  );
26966
- const handleScroll = (0, import_react5.useCallback)(
27080
+ const handleScroll = (0, import_react6.useCallback)(
26967
27081
  (event) => {
26968
27082
  trackMobileChromeByOffset(event.nativeEvent?.offsetY ?? 0);
26969
27083
  },
26970
27084
  [trackMobileChromeByOffset]
26971
27085
  );
26972
- const handleTap = (0, import_react5.useCallback)(() => {
27086
+ const handleTap = (0, import_react6.useCallback)(() => {
26973
27087
  setSelectedAnnotation(null);
26974
27088
  const nextVisible = resolvePageTapChromeVisibility({
26975
27089
  chromeVisible: chromeVisibleRef.current,
@@ -26979,7 +27093,7 @@ function DedicatedIosPdfViewer({
26979
27093
  });
26980
27094
  if (nextVisible !== null) setMobileChromeVisible(nextVisible);
26981
27095
  }, [activeTool, selectionActive, setMobileChromeVisible, setSelectedAnnotation]);
26982
- const handleDeleteAnnotation = (0, import_react5.useCallback)(
27096
+ const handleDeleteAnnotation = (0, import_react6.useCallback)(
26983
27097
  (annotationId) => {
26984
27098
  deleteAnnotationAndClearSelection(
26985
27099
  annotationId,
@@ -26994,12 +27108,12 @@ function DedicatedIosPdfViewer({
26994
27108
  maxWidth: resolvedMaxPageWidth,
26995
27109
  alignSelf: "center"
26996
27110
  } : void 0;
26997
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native5.View, { style: styles5.container, children: [
26998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
27111
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native5.View, { style: styles5.container, children: [
27112
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PdfNoteChooser, { notes: pendingNotes, title: t.annotationNote, cancel: t.cancel, onClose: () => setPendingNotes([]), onSelect: (id) => {
26999
27113
  setPendingNotes([]);
27000
27114
  setSelectedAnnotation(id);
27001
27115
  } }),
27002
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
27116
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27003
27117
  import_engine_native3.PapyrusPdfDocumentView,
27004
27118
  {
27005
27119
  style: [styles5.viewer, cappedViewerStyle],
@@ -27068,22 +27182,22 @@ function DedicatedIosPdfViewer({
27068
27182
  onInkToolPickerVisibilityChange: handleInkToolPickerVisibilityChange
27069
27183
  }
27070
27184
  ),
27071
- selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native5.View, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
27185
+ selection && !supportsNativeEditMenu && onDefineSelection && shouldShowDefineSelection(selection.text, defineSelectionMode) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native5.View, { style: styles5.selectionFallback, pointerEvents: "box-none", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27072
27186
  import_react_native5.Pressable,
27073
27187
  {
27074
27188
  onPress: defineSelection,
27075
27189
  style: styles5.fallbackButton,
27076
27190
  accessibilityRole: "button",
27077
27191
  accessibilityLabel: t.define,
27078
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native5.Text, { style: styles5.fallbackButtonText, children: t.define })
27192
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native5.Text, { style: styles5.fallbackButtonText, children: t.define })
27079
27193
  }
27080
27194
  ) }),
27081
- fallbackDeleteAnnotation && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
27195
+ fallbackDeleteAnnotation && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27082
27196
  import_react_native5.View,
27083
27197
  {
27084
27198
  style: styles5.annotationDeleteFallback,
27085
27199
  pointerEvents: "box-none",
27086
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
27200
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27087
27201
  import_react_native5.Pressable,
27088
27202
  {
27089
27203
  onPress: () => handleDeleteAnnotation(fallbackDeleteAnnotation.id),
@@ -27091,7 +27205,7 @@ function DedicatedIosPdfViewer({
27091
27205
  accessibilityRole: "button",
27092
27206
  accessibilityLabel: t.deleteAnnotation,
27093
27207
  hitSlop: 8,
27094
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native5.Text, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
27208
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native5.Text, { style: styles5.annotationDeleteButtonText, children: t.deleteAnnotation })
27095
27209
  }
27096
27210
  )
27097
27211
  }
@@ -27154,7 +27268,7 @@ var styles5 = import_react_native5.StyleSheet.create({
27154
27268
  });
27155
27269
 
27156
27270
  // components/NativePdfDocumentViewer.tsx
27157
- var import_jsx_runtime8 = require("react/jsx-runtime");
27271
+ var import_jsx_runtime9 = require("react/jsx-runtime");
27158
27272
  function NativePdfDocumentViewer({
27159
27273
  engine,
27160
27274
  documentId,
@@ -27167,7 +27281,7 @@ function NativePdfDocumentViewer({
27167
27281
  import_react_native6.Platform.OS
27168
27282
  );
27169
27283
  if (implementation === "android") {
27170
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27284
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
27171
27285
  DedicatedAndroidPdfViewer,
27172
27286
  {
27173
27287
  engine,
@@ -27180,7 +27294,7 @@ function NativePdfDocumentViewer({
27180
27294
  );
27181
27295
  }
27182
27296
  if (implementation === "ios") {
27183
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
27297
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
27184
27298
  DedicatedIosPdfViewer,
27185
27299
  {
27186
27300
  engine,
@@ -27234,26 +27348,6 @@ var resolveMobileChromeOffsets = (insets) => ({
27234
27348
  right: MOBILE_CHROME_METRICS.screenPadding + Math.max(0, insets.right)
27235
27349
  });
27236
27350
 
27237
- // components/PapyrusSafeArea.tsx
27238
- var import_react6 = __toESM(require("react"));
27239
- var import_react_native_safe_area_context = require("react-native-safe-area-context");
27240
- var import_jsx_runtime9 = require("react/jsx-runtime");
27241
- var papyrusSafeAreaContext = import_react_native_safe_area_context.SafeAreaInsetsContext;
27242
- var ZERO_SAFE_AREA_INSETS = {
27243
- top: 0,
27244
- bottom: 0,
27245
- left: 0,
27246
- right: 0
27247
- };
27248
- var usePapyrusSafeAreaInsets = () => (0, import_react6.useContext)(papyrusSafeAreaContext) ?? ZERO_SAFE_AREA_INSETS;
27249
- function PapyrusSafeAreaBoundary({
27250
- children
27251
- }) {
27252
- const insets = (0, import_react6.useContext)(papyrusSafeAreaContext);
27253
- if (insets) return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
27254
- return import_react6.default.createElement(import_react_native_safe_area_context.SafeAreaProvider, null, children);
27255
- }
27256
-
27257
27351
  // components/NativeTextDocumentViewer.tsx
27258
27352
  var import_jsx_runtime10 = require("react/jsx-runtime");
27259
27353
  function NativeTextDocumentViewer({
@@ -27802,6 +27896,7 @@ var scrollViewerListToOffset = (list, offset, animated) => {
27802
27896
  list.scrollToOffset?.({ offset, animated });
27803
27897
  };
27804
27898
  var Viewer = ({
27899
+ documentType,
27805
27900
  documentId,
27806
27901
  engine,
27807
27902
  maxPageWidth,
@@ -29329,14 +29424,8 @@ var Viewer = ({
29329
29424
  },
29330
29425
  [mobilePerf, perfEnabled, scrollPerfSession]
29331
29426
  );
29332
- const handleWebViewScroll = (0, import_react9.useCallback)(
29333
- (_offsetY) => {
29334
- if (!chromeVisibleRef.current) {
29335
- setMobileChromeVisible(true, "scroll.webview.recover");
29336
- }
29337
- },
29338
- [setMobileChromeVisible]
29339
- );
29427
+ const handleWebViewScroll = (0, import_react9.useCallback)((_offsetY) => {
29428
+ }, []);
29340
29429
  const handlePageTap = (0, import_react9.useCallback)(() => {
29341
29430
  const nextVisible = resolvePageTapChromeVisibility({
29342
29431
  chromeVisible: chromeVisibleRef.current,
@@ -29558,6 +29647,7 @@ var Viewer = ({
29558
29647
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native9.View, { style: [styles8.container, isDark && styles8.containerDark], children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
29559
29648
  WebViewViewer_default,
29560
29649
  {
29650
+ documentType,
29561
29651
  engine,
29562
29652
  documentId,
29563
29653
  onDefineSelection,
@@ -30104,6 +30194,7 @@ var styles9 = import_react_native11.StyleSheet.create({
30104
30194
  // components/PageJumpModal.tsx
30105
30195
  var import_jsx_runtime14 = require("react/jsx-runtime");
30106
30196
  function PageJumpModal({
30197
+ documentType,
30107
30198
  visible,
30108
30199
  currentPage,
30109
30200
  pageCount,
@@ -30130,8 +30221,8 @@ function PageJumpModal({
30130
30221
  isDark,
30131
30222
  maxHeight: 300,
30132
30223
  showHeader: true,
30133
- title: "Ir para p\xE1gina",
30134
- closeAccessibilityLabel: "Close page jump",
30224
+ title: documentType === "epub" ? "Ir para cap\xEDtulo" : "Ir para p\xE1gina",
30225
+ closeAccessibilityLabel: "Fechar navega\xE7\xE3o",
30135
30226
  sheetStyle: {
30136
30227
  paddingHorizontal: 18,
30137
30228
  paddingBottom: 18,
@@ -30159,7 +30250,7 @@ function PageJumpModal({
30159
30250
  }
30160
30251
  ],
30161
30252
  onSubmitEditing: confirmJump,
30162
- accessibilityLabel: "Page jump input",
30253
+ accessibilityLabel: documentType === "epub" ? "N\xFAmero do cap\xEDtulo" : "N\xFAmero da p\xE1gina",
30163
30254
  testID: "papyrus-page-jump-input"
30164
30255
  }
30165
30256
  ),
@@ -30214,6 +30305,7 @@ var styles10 = import_react_native12.StyleSheet.create({
30214
30305
  var import_jsx_runtime15 = require("react/jsx-runtime");
30215
30306
  var Topbar = ({
30216
30307
  engine,
30308
+ documentType,
30217
30309
  onOpenSettings,
30218
30310
  onOpenOverflow,
30219
30311
  title,
@@ -30234,6 +30326,12 @@ var Topbar = ({
30234
30326
  locale
30235
30327
  } = (0, import_core12.useViewerStore)();
30236
30328
  const inkSession = useNativeInkSession();
30329
+ const chromeVisible = mobileChromeVisible || inkSession.active;
30330
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
30331
+ const chromeMotion = (0, import_react_native_reanimated2.useAnimatedStyle)(() => {
30332
+ "worklet";
30333
+ return { opacity: chromeProgress.value };
30334
+ });
30237
30335
  const t = getStrings(locale);
30238
30336
  const progress = useNativeInkMotion(inkSession.active, inkSession.supported);
30239
30337
  const settingsMotion = (0, import_react_native_reanimated2.useAnimatedStyle)(() => {
@@ -30289,20 +30387,23 @@ var Topbar = ({
30289
30387
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconSettings, { size: MOBILE_CHROME_METRICS.iconSize, color: isDark ? "#e5e7eb" : "#111827" })
30290
30388
  }
30291
30389
  );
30292
- if (!mobileChromeVisible && !inkSession.active) return null;
30390
+ if (!chromeVisible && documentType !== "epub") return null;
30293
30391
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
30294
30392
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
30295
- import_react_native13.View,
30393
+ import_react_native_reanimated2.default.View,
30296
30394
  {
30297
30395
  style: [
30298
30396
  styles11.chromeFrame,
30397
+ chromeMotion,
30299
30398
  {
30300
30399
  paddingTop: insets.top,
30301
30400
  paddingLeft: MOBILE_CHROME_METRICS.screenPadding + insets.left,
30302
30401
  paddingRight: MOBILE_CHROME_METRICS.screenPadding + insets.right
30303
30402
  }
30304
30403
  ],
30305
- pointerEvents: "box-none",
30404
+ pointerEvents: chromeVisible ? "box-none" : "none",
30405
+ accessibilityElementsHidden: !chromeVisible,
30406
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
30306
30407
  testID: "papyrus-floating-top-controls",
30307
30408
  children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
30308
30409
  import_react_native13.View,
@@ -30449,6 +30550,7 @@ var Topbar = ({
30449
30550
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
30450
30551
  PageJumpModal,
30451
30552
  {
30553
+ documentType,
30452
30554
  visible: jumpModalOpen,
30453
30555
  currentPage,
30454
30556
  pageCount,
@@ -32699,7 +32801,27 @@ var AnnotationEditor = ({ documentId }) => {
32699
32801
  editing ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
32700
32802
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.TextInput, { 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" }] }),
32701
32803
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.View, { style: styles14.options, children: COLORS.map((value) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Pressable, { accessibilityRole: "button", accessibilityLabel: `${t.annotationColor} ${value}`, accessibilityState: { selected: color === value }, onPress: () => setColor(value), style: [styles14.color, { backgroundColor: value, borderColor: color === value ? accentColor : "transparent" }] }, value)) }),
32702
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.View, { style: styles14.options, children: [["highlight", t.annotationHighlight], ["underline", t.annotationUnderline], ["strikeout", t.annotationStrikeout], ["none", t.annotationIndicatorOnly]].map(([style, label]) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Pressable, { onPress: () => setMarkup(style), accessibilityRole: "button", accessibilityState: { selected: markup === style }, style: [styles14.button, markup === style && { borderColor: accentColor, borderWidth: 1 }], children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: textStyle, children: label }) }, style)) })
32804
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.View, { style: styles14.markupOptions, children: [
32805
+ ["highlight", t.annotationHighlight, IconHighlight],
32806
+ ["underline", t.annotationUnderline, IconUnderline],
32807
+ ["strikeout", t.annotationStrikeout, IconStrikeout],
32808
+ ["none", t.annotationIndicatorOnly, IconComment]
32809
+ ].map(([style, label, Icon]) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
32810
+ import_react_native16.Pressable,
32811
+ {
32812
+ onPress: () => setMarkup(style),
32813
+ accessibilityRole: "button",
32814
+ accessibilityLabel: label,
32815
+ accessibilityState: { selected: markup === style },
32816
+ testID: `annotation-style-${style}`,
32817
+ style: [styles14.markupButton, { backgroundColor: dark ? "#242936" : "#f1f5f9", borderColor: markup === style ? accentColor : "transparent" }],
32818
+ children: [
32819
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.View, { accessible: false, importantForAccessibility: "no-hide-descendants", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon, { size: 22, color: markup === style ? accentColor : textStyle.color }) }),
32820
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: [styles14.markupLabel, textStyle], children: style === "none" ? locale === "pt-BR" ? "Indicador" : "Indicator" : label })
32821
+ ]
32822
+ },
32823
+ style
32824
+ )) })
32703
32825
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native16.Text, { style: [styles14.note, textStyle], selectable: true, children: (0, import_core15.getAnnotationNote)(annotation) || t.notePlaceholder })
32704
32826
  ] }),
32705
32827
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native16.View, { style: styles14.actions, children: [
@@ -32722,7 +32844,7 @@ var AnnotationEditor = ({ documentId }) => {
32722
32844
  ] })
32723
32845
  ] }) });
32724
32846
  };
32725
- var styles14 = import_react_native16.StyleSheet.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 } });
32847
+ var styles14 = import_react_native16.StyleSheet.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 } });
32726
32848
  var AnnotationEditor_default = AnnotationEditor;
32727
32849
 
32728
32850
  // components/BottomBar.tsx
@@ -32793,6 +32915,8 @@ var BottomBar = ({
32793
32915
  const {
32794
32916
  activeMobileDestination,
32795
32917
  viewMode,
32918
+ epubReadingMode,
32919
+ epubLocation,
32796
32920
  comicLayoutMode,
32797
32921
  currentPage,
32798
32922
  pageCount,
@@ -32810,7 +32934,7 @@ var BottomBar = ({
32810
32934
  const supportsInkChrome = documentType === "pdf" && inkSession.supported;
32811
32935
  const drawing = supportsInkChrome && inkSession.active;
32812
32936
  const dockVisible = mobileChromeVisible && mobileDockVisible && !drawing;
32813
- const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome);
32937
+ const dockProgress = useNativeInkMotion(dockVisible, supportsInkChrome || documentType === "epub");
32814
32938
  const dockMotion = (0, import_react_native_reanimated3.useAnimatedStyle)(() => {
32815
32939
  "worklet";
32816
32940
  return {
@@ -32832,7 +32956,7 @@ var BottomBar = ({
32832
32956
  activeMobileDestination,
32833
32957
  toolDockOpen
32834
32958
  });
32835
- const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : viewMode === "single");
32959
+ const paginated = documentType !== "text" && (documentType === "comic" ? comicLayoutMode === "single" : documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single");
32836
32960
  if (paginated) {
32837
32961
  layout.leftSlots.push(...layout.rightSlots.filter((slot) => slot.key === "search"));
32838
32962
  layout.rightSlots = [];
@@ -32901,7 +33025,7 @@ var BottomBar = ({
32901
33025
  onPress: onOpenSettings
32902
33026
  }
32903
33027
  };
32904
- if (!dockVisible && !supportsInkChrome) return null;
33028
+ if (!dockVisible && !supportsInkChrome && documentType !== "epub") return null;
32905
33029
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
32906
33030
  import_react_native_reanimated3.default.View,
32907
33031
  {
@@ -32967,13 +33091,9 @@ var BottomBar = ({
32967
33091
  ],
32968
33092
  testID: "papyrus-floating-bottom-dock",
32969
33093
  children: paginated ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
32970
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "P\xE1gina anterior" : "Previous page", disabled: !dockVisible || !onTurnPage && currentPage <= 1, onPress: () => turnPage(-1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
32971
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Ir para p\xE1gina" : "Go to page", onPress: onOpenPages, style: [styles15.iconOnlyItem, { minWidth: 56 }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native17.Text, { style: { color: iconColor(false), fontWeight: "700", fontSize: 13, lineHeight: 18, includeFontPadding: false }, children: [
32972
- currentPage,
32973
- "/",
32974
- pageCount
32975
- ] }) }),
32976
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Pr\xF3xima p\xE1gina" : "Next page", disabled: !dockVisible || !onTurnPage && currentPage >= pageCount, onPress: () => turnPage(1), style: styles15.iconOnlyItem, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
33094
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { 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__ */ (0, import_jsx_runtime19.jsx)(IconChevronLeft, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) }),
33095
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { accessibilityRole: "button", accessibilityLabel: locale === "pt-BR" ? "Ir para p\xE1gina" : "Go to page", onPress: onOpenPages, style: [styles15.iconOnlyItem, { minWidth: 56 }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Text, { 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}` }) }),
33096
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native17.Pressable, { 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__ */ (0, import_jsx_runtime19.jsx)(IconChevronRight, { size: MOBILE_CHROME_METRICS.iconSize, color: iconColor(false) }) })
32977
33097
  ] }) : layout.rightSlots.map((slot) => {
32978
33098
  const meta = slotMeta[slot.key];
32979
33099
  const Icon = meta.icon;
@@ -33148,6 +33268,7 @@ var SettingsSheet = ({
33148
33268
  }) => {
33149
33269
  const {
33150
33270
  viewMode,
33271
+ epubReadingMode,
33151
33272
  uiTheme,
33152
33273
  zoom,
33153
33274
  setDocumentState,
@@ -33159,12 +33280,16 @@ var SettingsSheet = ({
33159
33280
  comicReadingDirection
33160
33281
  } = (0, import_core17.useViewerStore)();
33161
33282
  const isDark = uiTheme === "dark";
33162
- const isPaged = viewMode === "single";
33283
+ const isPaged = documentType === "epub" ? epubReadingMode === "paged" : viewMode === "single";
33163
33284
  const isDouble = viewMode === "double";
33164
33285
  const t = getStrings(locale);
33165
33286
  const { height: windowHeight } = (0, import_react_native18.useWindowDimensions)();
33166
33287
  const sheetMaxHeight = getSettingsSheetMaxHeight(windowHeight);
33167
33288
  const handleTransition = (mode) => {
33289
+ if (documentType === "epub") {
33290
+ setDocumentState({ epubReadingMode: mode === "paged" ? "paged" : "chapter-scroll" });
33291
+ return;
33292
+ }
33168
33293
  if (mode === "paged") {
33169
33294
  setDocumentState({ viewMode: "single" });
33170
33295
  return;
@@ -33388,7 +33513,7 @@ var SettingsSheet = ({
33388
33513
  isDark && styles16.optionTextDark,
33389
33514
  (!isPaged || isDouble) && styles16.optionTextActive
33390
33515
  ],
33391
- children: t.continuous
33516
+ children: documentType === "epub" && locale === "pt-BR" ? "Rolagem por cap\xEDtulo" : t.continuous
33392
33517
  }
33393
33518
  )
33394
33519
  }
@@ -33418,7 +33543,7 @@ var SettingsSheet = ({
33418
33543
  )
33419
33544
  ] })
33420
33545
  ] }),
33421
- documentType !== "comic" && documentType !== "text" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native18.View, { style: styles16.section, children: [
33546
+ documentType === "pdf" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native18.View, { style: styles16.section, children: [
33422
33547
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
33423
33548
  import_react_native18.Text,
33424
33549
  {
@@ -34296,6 +34421,7 @@ var styles20 = import_react_native22.StyleSheet.create({
34296
34421
  // components/ProgressPill.tsx
34297
34422
  var import_react18 = require("react");
34298
34423
  var import_react_native23 = require("react-native");
34424
+ var import_react_native_reanimated4 = __toESM(require("react-native-reanimated"));
34299
34425
  var import_core21 = require("@papyrus-sdk/core");
34300
34426
 
34301
34427
  // components/progressPillMode.ts
@@ -34329,12 +34455,20 @@ function ProgressPill({
34329
34455
  textLength,
34330
34456
  comicLayoutMode,
34331
34457
  viewMode,
34458
+ epubReadingMode,
34459
+ epubLocation,
34332
34460
  locale,
34333
34461
  uiTheme,
34334
34462
  accentColor,
34335
34463
  mobileChromeVisible,
34336
34464
  mobileProgressPillVisible
34337
34465
  } = (0, import_core21.useViewerStore)();
34466
+ const chromeVisible = mobileChromeVisible && mobileProgressPillVisible;
34467
+ const chromeProgress = useNativeInkMotion(chromeVisible, documentType === "epub");
34468
+ const chromeMotion = (0, import_react_native_reanimated4.useAnimatedStyle)(() => {
34469
+ "worklet";
34470
+ return { opacity: chromeProgress.value };
34471
+ });
34338
34472
  const t = getStrings(locale);
34339
34473
  const isDark = uiTheme === "dark";
34340
34474
  const offsets = resolveMobileChromeOffsets(usePapyrusSafeAreaInsets());
@@ -34379,10 +34513,10 @@ function ProgressPill({
34379
34513
  return `${displayedPage}/${pageCount || 0}`;
34380
34514
  }
34381
34515
  if (documentType === "epub") {
34382
- return `Cap. ${displayedPage} \xB7 ${percent}%`;
34516
+ return `Cap. ${displayedPage} \xB7 ${scrubPreviewPage === null && epubLocation ? clampPercent(epubLocation.progress * 100) : percent}%`;
34383
34517
  }
34384
34518
  return `${percent}%`;
34385
- }, [displayedPage, documentType, pageCount]);
34519
+ }, [displayedPage, documentType, pageCount, epubLocation, scrubPreviewPage]);
34386
34520
  const thumbTop = resolvePageScrubberThumbTop({
34387
34521
  currentPage,
34388
34522
  trackHeight,
@@ -34424,7 +34558,7 @@ function ProgressPill({
34424
34558
  },
34425
34559
  []
34426
34560
  );
34427
- if (!shouldRenderPageScrubber({
34561
+ if (!(documentType === "epub" && mobileProgressPillVisible) && !shouldRenderPageScrubber({
34428
34562
  mobileChromeVisible,
34429
34563
  mobileProgressPillVisible,
34430
34564
  isScrubbing: isScrubbingRef.current
@@ -34455,7 +34589,7 @@ function ProgressPill({
34455
34589
  }
34456
34590
  );
34457
34591
  }
34458
- const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : viewMode;
34592
+ const progressViewMode = documentType === "comic" ? comicLayoutMode === "single" ? "single" : "continuous" : documentType === "epub" ? epubReadingMode === "paged" ? "single" : "continuous" : viewMode;
34459
34593
  const pillMode = resolveProgressPillMode(progressViewMode, currentPage, pageCount);
34460
34594
  if (pillMode.kind === "navigation" && navigationInDock) return null;
34461
34595
  if (pillMode.kind === "navigation") {
@@ -34646,11 +34780,14 @@ function ProgressPill({
34646
34780
  }
34647
34781
  const responderPanHandlers = scrubberResponderRef.current?.panHandlers ?? {};
34648
34782
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
34649
- import_react_native23.View,
34783
+ import_react_native_reanimated4.default.View,
34650
34784
  {
34651
- pointerEvents: "box-none",
34785
+ pointerEvents: chromeVisible ? "box-none" : "none",
34786
+ accessibilityElementsHidden: !chromeVisible,
34787
+ importantForAccessibility: chromeVisible ? "auto" : "no-hide-descendants",
34652
34788
  style: [
34653
34789
  styles21.frame,
34790
+ chromeMotion,
34654
34791
  resolvePageScrubberOverlayStyle(),
34655
34792
  {
34656
34793
  top: offsets.progress,
@@ -35379,6 +35516,7 @@ function ReadingShell({
35379
35516
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35380
35517
  Topbar_default,
35381
35518
  {
35519
+ documentType,
35382
35520
  engine,
35383
35521
  title,
35384
35522
  onOpenSettings: () => openDestination("display"),
@@ -35389,6 +35527,7 @@ function ReadingShell({
35389
35527
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_native26.View, { style: styles24.viewerStage, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35390
35528
  Viewer_default,
35391
35529
  {
35530
+ documentType,
35392
35531
  engine,
35393
35532
  ...viewerProps,
35394
35533
  pageScrubActive
@@ -35513,6 +35652,7 @@ function ReadingShell({
35513
35652
  /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
35514
35653
  PageJumpModal,
35515
35654
  {
35655
+ documentType,
35516
35656
  visible: pageJumpOpen,
35517
35657
  currentPage,
35518
35658
  pageCount,