@nypl/web-reader 5.0.0-alpha.0 → 5.0.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/README.md CHANGED
@@ -123,6 +123,18 @@ There are two different injectables props you can pass to the web reader.
123
123
 
124
124
  Your app can provide both props or only one. The reader will decide which one to load into the iframe based on the book format defined in the webpub manifest.
125
125
 
126
+ ## Required CSS for the PDF Reader (Text & Annotation Layers)
127
+
128
+ When rendering PDFs the library relies on `react-pdf`'s text and annotation layer styles.
129
+
130
+ To avoid importing global CSS from inside distributed JS in Next.js applications, you must import global CSS only from the app root (`pages/_app.js` / `pages/_app.tsx` or `app/layout.tsx`). After installing `@nypl/web-reader`, import the following CSS from your application root:
131
+
132
+ ```js
133
+ // pages/_app.tsx or app/layout.tsx
134
+ import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
135
+ import 'react-pdf/dist/esm/Page/TextLayer.css';
136
+ ```
137
+
126
138
  ## Other Injectables
127
139
 
128
140
  You can import and inject other files into the `<WebReader />` to customize behavior. For example, in Open eBooks, we import some [custom JavaScript](https://github.com/NYPL/ereading-clients/blob/staging/apps/oew/src/components/theme-ui/WebReader.tsx#L65) to disable right clicking & copying copywritten content.
package/dist/index.d.mts CHANGED
@@ -35,9 +35,9 @@ interface Locations {
35
35
 
36
36
  declare const ReadiumWebpubContext = "http://readium.org/webpub/default.jsonld";
37
37
  declare const IS_DEV: boolean;
38
- declare const HEADER_HEIGHT = 48;
39
- declare const CHROME_HEIGHT = 48;
40
- declare const DEFAULT_HEIGHT = "calc(100vh - 48px)";
38
+ declare const HEADER_HEIGHT = 49;
39
+ declare const CHROME_HEIGHT = 49;
40
+ declare const DEFAULT_HEIGHT = "calc(100vh - 49px)";
41
41
  declare const DEFAULT_SHOULD_GROW_WHEN_SCROLLING = true;
42
42
  declare const READER_MARGIN = 16;
43
43
  declare const DEFAULT_SETTINGS: ReaderSettings;
@@ -70,6 +70,7 @@ declare const FONT_DETAILS: {
70
70
  fontWeight: string;
71
71
  };
72
72
  };
73
+ declare const IN_VIEW_DELAY_MS = 150;
73
74
  declare const LOCAL_STORAGE_SETTINGS_KEY = "web-reader-settings";
74
75
  declare const LOCAL_STORAGE_LOCATIONS_KEY = "web-reader-locations";
75
76
  declare const MAIN_CONTENT_ID = "mainContent";
@@ -546,4 +547,4 @@ type WebReaderProps = UseWebReaderArguments<string | Uint8Array>;
546
547
  declare const WebReaderWithoutBoundary: FC<WebReaderProps>;
547
548
  declare const WebReader: FC<WebReaderProps>;
548
549
 
549
- export { CHROME_HEIGHT, DEFAULT_FIT_MODE, DEFAULT_FONT_HEIGHT, DEFAULT_FONT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SETTINGS, DEFAULT_SHOULD_GROW_WHEN_SCROLLING, FONT_DETAILS, HEADER_HEIGHT, IS_DEV, LOCAL_STORAGE_LOCATIONS_KEY, LOCAL_STORAGE_SETTINGS_KEY, MAIN_CONTENT_ID, READER_MARGIN, type ReadiumLink, ReadiumWebpubContext, type WebReaderProps, WebReaderWithoutBoundary, type WebpubManifest, addTocToManifest, clearWebReaderLocalStorage, WebReader as default, getTheme, useColorModeValue, useHtmlReader, usePdfReader, useWebReader };
550
+ export { CHROME_HEIGHT, DEFAULT_FIT_MODE, DEFAULT_FONT_HEIGHT, DEFAULT_FONT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SETTINGS, DEFAULT_SHOULD_GROW_WHEN_SCROLLING, FONT_DETAILS, HEADER_HEIGHT, IN_VIEW_DELAY_MS, IS_DEV, LOCAL_STORAGE_LOCATIONS_KEY, LOCAL_STORAGE_SETTINGS_KEY, MAIN_CONTENT_ID, READER_MARGIN, type ReadiumLink, ReadiumWebpubContext, type WebReaderProps, WebReaderWithoutBoundary, type WebpubManifest, addTocToManifest, clearWebReaderLocalStorage, WebReader as default, getTheme, useColorModeValue, useHtmlReader, usePdfReader, useWebReader };
package/dist/index.d.ts CHANGED
@@ -35,9 +35,9 @@ interface Locations {
35
35
 
36
36
  declare const ReadiumWebpubContext = "http://readium.org/webpub/default.jsonld";
37
37
  declare const IS_DEV: boolean;
38
- declare const HEADER_HEIGHT = 48;
39
- declare const CHROME_HEIGHT = 48;
40
- declare const DEFAULT_HEIGHT = "calc(100vh - 48px)";
38
+ declare const HEADER_HEIGHT = 49;
39
+ declare const CHROME_HEIGHT = 49;
40
+ declare const DEFAULT_HEIGHT = "calc(100vh - 49px)";
41
41
  declare const DEFAULT_SHOULD_GROW_WHEN_SCROLLING = true;
42
42
  declare const READER_MARGIN = 16;
43
43
  declare const DEFAULT_SETTINGS: ReaderSettings;
@@ -70,6 +70,7 @@ declare const FONT_DETAILS: {
70
70
  fontWeight: string;
71
71
  };
72
72
  };
73
+ declare const IN_VIEW_DELAY_MS = 150;
73
74
  declare const LOCAL_STORAGE_SETTINGS_KEY = "web-reader-settings";
74
75
  declare const LOCAL_STORAGE_LOCATIONS_KEY = "web-reader-locations";
75
76
  declare const MAIN_CONTENT_ID = "mainContent";
@@ -546,4 +547,4 @@ type WebReaderProps = UseWebReaderArguments<string | Uint8Array>;
546
547
  declare const WebReaderWithoutBoundary: FC<WebReaderProps>;
547
548
  declare const WebReader: FC<WebReaderProps>;
548
549
 
549
- export { CHROME_HEIGHT, DEFAULT_FIT_MODE, DEFAULT_FONT_HEIGHT, DEFAULT_FONT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SETTINGS, DEFAULT_SHOULD_GROW_WHEN_SCROLLING, FONT_DETAILS, HEADER_HEIGHT, IS_DEV, LOCAL_STORAGE_LOCATIONS_KEY, LOCAL_STORAGE_SETTINGS_KEY, MAIN_CONTENT_ID, READER_MARGIN, type ReadiumLink, ReadiumWebpubContext, type WebReaderProps, WebReaderWithoutBoundary, type WebpubManifest, addTocToManifest, clearWebReaderLocalStorage, WebReader as default, getTheme, useColorModeValue, useHtmlReader, usePdfReader, useWebReader };
550
+ export { CHROME_HEIGHT, DEFAULT_FIT_MODE, DEFAULT_FONT_HEIGHT, DEFAULT_FONT_WIDTH, DEFAULT_HEIGHT, DEFAULT_SETTINGS, DEFAULT_SHOULD_GROW_WHEN_SCROLLING, FONT_DETAILS, HEADER_HEIGHT, IN_VIEW_DELAY_MS, IS_DEV, LOCAL_STORAGE_LOCATIONS_KEY, LOCAL_STORAGE_SETTINGS_KEY, MAIN_CONTENT_ID, READER_MARGIN, type ReadiumLink, ReadiumWebpubContext, type WebReaderProps, WebReaderWithoutBoundary, type WebpubManifest, addTocToManifest, clearWebReaderLocalStorage, WebReader as default, getTheme, useColorModeValue, useHtmlReader, usePdfReader, useWebReader };
package/dist/index.js CHANGED
@@ -814,6 +814,7 @@ __export(src_exports, {
814
814
  DEFAULT_SHOULD_GROW_WHEN_SCROLLING: () => DEFAULT_SHOULD_GROW_WHEN_SCROLLING,
815
815
  FONT_DETAILS: () => FONT_DETAILS,
816
816
  HEADER_HEIGHT: () => HEADER_HEIGHT,
817
+ IN_VIEW_DELAY_MS: () => IN_VIEW_DELAY_MS,
817
818
  IS_DEV: () => IS_DEV,
818
819
  LOCAL_STORAGE_LOCATIONS_KEY: () => LOCAL_STORAGE_LOCATIONS_KEY,
819
820
  LOCAL_STORAGE_SETTINGS_KEY: () => LOCAL_STORAGE_SETTINGS_KEY,
@@ -1389,7 +1390,7 @@ var React29 = __toESM(require("react"));
1389
1390
  // src/constants.ts
1390
1391
  var ReadiumWebpubContext = "http://readium.org/webpub/default.jsonld";
1391
1392
  var IS_DEV = process.env.NODE_ENV === "development";
1392
- var HEADER_HEIGHT = 48;
1393
+ var HEADER_HEIGHT = 49;
1393
1394
  var CHROME_HEIGHT = HEADER_HEIGHT;
1394
1395
  var DEFAULT_HEIGHT = `calc(100vh - ${CHROME_HEIGHT}px)`;
1395
1396
  var DEFAULT_SHOULD_GROW_WHEN_SCROLLING = true;
@@ -1429,6 +1430,7 @@ var FONT_DETAILS = {
1429
1430
  fontWeight: "regular"
1430
1431
  }
1431
1432
  };
1433
+ var IN_VIEW_DELAY_MS = 150;
1432
1434
  var LOCAL_STORAGE_SETTINGS_KEY = "web-reader-settings";
1433
1435
  var LOCAL_STORAGE_LOCATIONS_KEY = "web-reader-locations";
1434
1436
  var MAIN_CONTENT_ID = "mainContent";
@@ -3515,10 +3517,7 @@ function createMultiStyleConfigHelpers(parts) {
3515
3517
  }
3516
3518
 
3517
3519
  // src/ui/theme/components/tabs.ts
3518
- var {
3519
- defineMultiStyleConfig,
3520
- definePartsStyle
3521
- } = createMultiStyleConfigHelpers(["root", "tab", "tablist"]);
3520
+ var { defineMultiStyleConfig, definePartsStyle } = createMultiStyleConfigHelpers(["root", "tab", "tablist"]);
3522
3521
  var getTabsStyle = (getColor2) => defineMultiStyleConfig({
3523
3522
  variants: {
3524
3523
  custom: definePartsStyle({
@@ -6129,14 +6128,7 @@ function Header(props) {
6129
6128
  var _a, _b, _c, _d;
6130
6129
  const [, toggleFullscreenHook] = useFullscreen();
6131
6130
  const [isFullscreen, setIsFullScreen] = (0, import_react84.useState)(false);
6132
- const {
6133
- navigator,
6134
- manifest,
6135
- type,
6136
- containerRef,
6137
- currentPage,
6138
- totalPages
6139
- } = props;
6131
+ const { navigator, manifest, type, containerRef, currentPage, totalPages } = props;
6140
6132
  const isAtStart = (_a = props.state) == null ? void 0 : _a.atStart;
6141
6133
  const isAtEnd = (_b = props.state) == null ? void 0 : _b.atEnd;
6142
6134
  const iconFill = useColorModeValue_default(
@@ -6756,12 +6748,8 @@ function setReflowableCss(iframeHtml, settings) {
6756
6748
  }
6757
6749
  function setFixedCss(iframeDocument, iframeContainer) {
6758
6750
  if (!iframeContainer) return;
6759
- let { contentWidth, contentHeight } = extractContentViewportSize(
6760
- iframeDocument
6761
- );
6762
- const { containerWidth, containerHeight } = extractContentContainerSize(
6763
- iframeContainer
6764
- );
6751
+ let { contentWidth, contentHeight } = extractContentViewportSize(iframeDocument);
6752
+ const { containerWidth, containerHeight } = extractContentContainerSize(iframeContainer);
6765
6753
  contentWidth = contentWidth != null ? contentWidth : containerWidth;
6766
6754
  contentHeight = contentHeight != null ? contentHeight : containerHeight;
6767
6755
  const scale = Math.min(
@@ -7328,9 +7316,7 @@ function useResource(manifest, state2, getContent, injectables, dispatch) {
7328
7316
  if (element) document2 == null ? void 0 : document2.head.appendChild(element);
7329
7317
  }
7330
7318
  injectJS(document2.body);
7331
- const iframeContainer = window.document.querySelector(
7332
- 'main [role="progressbar"]'
7333
- );
7319
+ const iframeContainer = window.document.querySelector('main [role="progressbar"]');
7334
7320
  const readerSettings = {
7335
7321
  colorMode: state2.settings.colorMode,
7336
7322
  fontSize: state2.settings.fontSize,
@@ -7695,129 +7681,6 @@ var ChakraPage = (0, import_react96.chakra)(
7695
7681
  );
7696
7682
  var ChakraPage_default = ChakraPage;
7697
7683
 
7698
- // src/PdfReader/ScrollPage.tsx
7699
- var import_react98 = __toESM(require("react"));
7700
- var import_react_intersection_observer = require("react-intersection-observer");
7701
- var Placeholder = ({ width, height, pageNumber }) => {
7702
- return /* @__PURE__ */ import_react98.default.createElement(
7703
- "div",
7704
- {
7705
- "data-page-number": pageNumber,
7706
- style: { width, height }
7707
- }
7708
- );
7709
- };
7710
- var ScrollPage = ({
7711
- scale,
7712
- pageNumber,
7713
- width,
7714
- height,
7715
- onLoadSuccess,
7716
- placeholderHeight,
7717
- placeholderWidth,
7718
- allowInView,
7719
- onInView,
7720
- fitMode,
7721
- rotate
7722
- }) => {
7723
- const { ref: loadRef, inView: loadInView } = (0, import_react_intersection_observer.useInView)({
7724
- threshold: 0,
7725
- triggerOnce: true
7726
- });
7727
- const { ref: visibilityRef, entry } = (0, import_react_intersection_observer.useInView)({
7728
- threshold: Array.from({ length: 11 }, (_, i) => i * 0.1),
7729
- triggerOnce: false
7730
- });
7731
- const setRefs = import_react98.default.useCallback(
7732
- (el) => {
7733
- if (typeof loadRef === "function") loadRef(el);
7734
- if (typeof visibilityRef === "function") visibilityRef(el);
7735
- },
7736
- [loadRef, visibilityRef]
7737
- );
7738
- const handleLoadSuccess = import_react98.default.useCallback(
7739
- (page) => {
7740
- onLoadSuccess(page);
7741
- },
7742
- [onLoadSuccess]
7743
- );
7744
- import_react98.default.useEffect(() => {
7745
- if (onInView && entry) {
7746
- onInView(pageNumber, entry.intersectionRatio || 0);
7747
- }
7748
- }, [entry, onInView, pageNumber]);
7749
- return /* @__PURE__ */ import_react98.default.createElement("div", { ref: setRefs }, loadInView ? /* @__PURE__ */ import_react98.default.createElement(
7750
- ChakraPage_default,
7751
- {
7752
- "data-page-number": pageNumber,
7753
- pageNumber,
7754
- scale,
7755
- width,
7756
- height,
7757
- onLoadSuccess: handleLoadSuccess,
7758
- fitMode,
7759
- rotate
7760
- }
7761
- ) : /* @__PURE__ */ import_react98.default.createElement(
7762
- Placeholder,
7763
- {
7764
- width: placeholderWidth,
7765
- height: placeholderHeight,
7766
- pageNumber
7767
- }
7768
- ));
7769
- };
7770
- var ScrollPage_default = ScrollPage;
7771
-
7772
- // src/PdfReader/useMeasure.tsx
7773
- var React49 = __toESM(require("react"));
7774
- var DEFAULT_DIMENSION = {
7775
- x: 0,
7776
- y: 0,
7777
- width: 0,
7778
- height: 0,
7779
- top: 0,
7780
- left: 0,
7781
- bottom: 0,
7782
- right: 0
7783
- };
7784
- function useMeasure() {
7785
- const [element, ref] = React49.useState(null);
7786
- const [rect, setRect] = React49.useState(DEFAULT_DIMENSION);
7787
- const observer = React49.useMemo(
7788
- () => new window.ResizeObserver(
7789
- (entries) => {
7790
- if (entries[0]) {
7791
- const {
7792
- x,
7793
- y,
7794
- width,
7795
- height,
7796
- top,
7797
- left,
7798
- bottom,
7799
- right
7800
- } = entries[0].contentRect;
7801
- setRect({ x, y, width, height, top, left, bottom, right });
7802
- }
7803
- }
7804
- ),
7805
- []
7806
- );
7807
- React49.useLayoutEffect(() => {
7808
- if (!element) return;
7809
- observer.observe(element);
7810
- return () => {
7811
- observer.disconnect();
7812
- };
7813
- }, [element, observer]);
7814
- return [ref, rect];
7815
- }
7816
-
7817
- // src/PdfReader/index.tsx
7818
- var import_AnnotationLayer = require("react-pdf/dist/Page/AnnotationLayer.css");
7819
- var import_TextLayer = require("react-pdf/dist/Page/TextLayer.css");
7820
-
7821
7684
  // src/PdfReader/lib.ts
7822
7685
  var SCALE_STEP = 0.1;
7823
7686
  var START_QUERY = "start";
@@ -8049,6 +7912,118 @@ function isStartOfResource(pageNumber, resourceHref) {
8049
7912
  return pageNumber === (startPage != null ? startPage : 1);
8050
7913
  }
8051
7914
 
7915
+ // src/PdfReader/ScrollPage.tsx
7916
+ var import_react98 = __toESM(require("react"));
7917
+ var import_react_intersection_observer = require("react-intersection-observer");
7918
+ var Placeholder = ({ width, height, pageNumber }) => {
7919
+ return /* @__PURE__ */ import_react98.default.createElement(
7920
+ "div",
7921
+ {
7922
+ "data-page-number": pageNumber,
7923
+ style: { width, height }
7924
+ }
7925
+ );
7926
+ };
7927
+ var ScrollPage = ({
7928
+ scale,
7929
+ pageNumber,
7930
+ width,
7931
+ height,
7932
+ onLoadSuccess,
7933
+ onPageRef,
7934
+ placeholderHeight,
7935
+ placeholderWidth,
7936
+ allowInView,
7937
+ onInView,
7938
+ fitMode,
7939
+ rotate
7940
+ }) => {
7941
+ const { ref: loadRef, inView: loadInView } = (0, import_react_intersection_observer.useInView)({
7942
+ threshold: 0,
7943
+ triggerOnce: true
7944
+ });
7945
+ const { ref: visibilityRef, entry } = (0, import_react_intersection_observer.useInView)({
7946
+ threshold: Array.from({ length: 11 }, (_, i) => i * 0.1),
7947
+ triggerOnce: false
7948
+ });
7949
+ const setRefs = import_react98.default.useCallback(
7950
+ (el) => {
7951
+ if (typeof loadRef === "function") loadRef(el);
7952
+ if (typeof visibilityRef === "function") visibilityRef(el);
7953
+ if (onPageRef) onPageRef(pageNumber, el);
7954
+ },
7955
+ [loadRef, onPageRef, pageNumber, visibilityRef]
7956
+ );
7957
+ const handleLoadSuccess = import_react98.default.useCallback(
7958
+ (page) => {
7959
+ onLoadSuccess(page);
7960
+ },
7961
+ [onLoadSuccess]
7962
+ );
7963
+ import_react98.default.useEffect(() => {
7964
+ if (allowInView && onInView && entry) {
7965
+ onInView(pageNumber, entry.intersectionRatio || 0);
7966
+ }
7967
+ }, [allowInView, entry, onInView, pageNumber]);
7968
+ return /* @__PURE__ */ import_react98.default.createElement("div", { ref: setRefs }, loadInView ? /* @__PURE__ */ import_react98.default.createElement(
7969
+ ChakraPage_default,
7970
+ {
7971
+ "data-page-number": pageNumber,
7972
+ pageNumber,
7973
+ scale,
7974
+ width,
7975
+ height,
7976
+ onLoadSuccess: handleLoadSuccess,
7977
+ fitMode,
7978
+ rotate
7979
+ }
7980
+ ) : /* @__PURE__ */ import_react98.default.createElement(
7981
+ Placeholder,
7982
+ {
7983
+ width: placeholderWidth,
7984
+ height: placeholderHeight,
7985
+ pageNumber
7986
+ }
7987
+ ));
7988
+ };
7989
+ var ScrollPage_default = ScrollPage;
7990
+
7991
+ // src/PdfReader/useMeasure.tsx
7992
+ var React49 = __toESM(require("react"));
7993
+ var DEFAULT_DIMENSION = {
7994
+ x: 0,
7995
+ y: 0,
7996
+ width: 0,
7997
+ height: 0,
7998
+ top: 0,
7999
+ left: 0,
8000
+ bottom: 0,
8001
+ right: 0
8002
+ };
8003
+ function useMeasure() {
8004
+ const [element, ref] = React49.useState(null);
8005
+ const [rect, setRect] = React49.useState(DEFAULT_DIMENSION);
8006
+ const observer = React49.useMemo(
8007
+ () => new window.ResizeObserver(
8008
+ (entries) => {
8009
+ if (entries[0]) {
8010
+ const { x, y, width, height, top, left, bottom, right } = entries[0].contentRect;
8011
+ setRect({ x, y, width, height, top, left, bottom, right });
8012
+ }
8013
+ }
8014
+ ),
8015
+ []
8016
+ );
8017
+ React49.useLayoutEffect(() => {
8018
+ if (!element) return;
8019
+ observer.observe(element);
8020
+ return () => {
8021
+ observer.disconnect();
8022
+ };
8023
+ }, [element, observer]);
8024
+ return [ref, rect];
8025
+ }
8026
+
8052
8027
  // src/PdfReader/index.tsx
8053
8028
  function usePdfReader(args) {
8054
8029
  var _a, _b, _c, _d, _e, _f;
@@ -8086,7 +8061,24 @@ function usePdfReader(args) {
8086
8061
  const isFetching = !state2.resource;
8087
8062
  const isParsed = typeof state2.numPages === "number";
8088
8063
  const [containerRef, containerSize] = useMeasure();
8089
- const [pageHeight, setPageHeight] = React50.useState(0);
8064
+ const documentContainerRef = React50.useRef(null);
8065
+ const pageRefs = React50.useRef(/* @__PURE__ */ new Map());
8066
+ const setPageRef = React50.useCallback(
8067
+ (pageNumber, element) => {
8068
+ if (element) {
8069
+ pageRefs.current.set(pageNumber, element);
8070
+ return;
8071
+ }
8072
+ pageRefs.current.delete(pageNumber);
8073
+ },
8074
+ []
8075
+ );
8076
+ const scrollState = React50.useRef({
8077
+ ratios: /* @__PURE__ */ new Map(),
8078
+ lastVisiblePage: state2.pageNumber,
8079
+ isInViewUpdate: false,
8080
+ lastProgrammaticNavAt: 0
8081
+ });
8090
8082
  React50.useEffect(() => {
8091
8083
  if (!webpubManifestUrl || !manifest) {
8092
8084
  return dispatch({ type: "ARGS_CHANGED", args: void 0 });
@@ -8159,13 +8151,6 @@ function usePdfReader(args) {
8159
8151
  var _a2;
8160
8152
  resizePage(containerSize, state2.fitMode, (_a2 = state2.rotation) != null ? _a2 : 0, state2.scale);
8161
8153
  }, [containerSize, resizePage, state2.fitMode, state2.rotation, state2.scale]);
8162
- React50.useEffect(() => {
8163
- if (pageHeight === 0 && state2.pdfWidth && state2.pdfHeight) {
8164
- const aspectRatio = state2.pdfHeight / state2.pdfWidth;
8165
- const initialPageHeight = (containerSize.width - READER_MARGIN) * aspectRatio;
8166
- setPageHeight(Math.round(initialPageHeight));
8167
- }
8168
- }, [state2.pdfWidth, state2.pdfHeight, containerSize.width, pageHeight]);
8169
8154
  React50.useEffect(() => {
8170
8155
  var _a2, _b2;
8171
8156
  const isFirstResource = state2.resourceIndex === 0;
@@ -8188,21 +8173,40 @@ function usePdfReader(args) {
8188
8173
  ]);
8189
8174
  React50.useEffect(() => {
8190
8175
  var _a2;
8191
- if (!((_a2 = state2.settings) == null ? void 0 : _a2.isScrolling)) return;
8192
- if (!state2.rendered) return;
8193
- process.nextTick(() => {
8194
- const page = document.querySelector(
8195
- `[data-page-number="${state2.pageNumber}"]`
8196
- );
8197
- page == null ? void 0 : page.scrollIntoView();
8198
- });
8176
+ if (!((_a2 = state2.settings) == null ? void 0 : _a2.isScrolling) || !state2.rendered) return;
8177
+ if (scrollState.current.isInViewUpdate) {
8178
+ scrollState.current.isInViewUpdate = false;
8179
+ return;
8180
+ }
8181
+ const documentContainer = documentContainerRef.current;
8182
+ const pageRef = pageRefs.current.get(state2.pageNumber);
8183
+ if (documentContainer && pageRef) {
8184
+ const containerRect = documentContainer.getBoundingClientRect();
8185
+ const pageRect = pageRef.getBoundingClientRect();
8186
+ documentContainer.scrollTo({
8187
+ top: documentContainer.scrollTop + (pageRect.top - containerRect.top)
8188
+ });
8189
+ }
8199
8190
  }, [state2.pageNumber, (_c = state2.settings) == null ? void 0 : _c.isScrolling, state2.rendered]);
8191
+ const beginProgrammaticNavigation = React50.useCallback(
8192
+ (pendingPage) => {
8193
+ const currentScrollState = scrollState.current;
8194
+ currentScrollState.lastVisiblePage = pendingPage;
8195
+ currentScrollState.lastProgrammaticNavAt = Date.now();
8196
+ currentScrollState.ratios.clear();
8197
+ },
8198
+ []
8199
+ );
8200
8200
  const goForward = React50.useCallback(() => __async(null, null, function* () {
8201
+ beginProgrammaticNavigation(
8202
+ state2.numPages ? Math.min(state2.pageNumber + 1, state2.numPages) : state2.pageNumber + 1
8203
+ );
8201
8204
  dispatch({ type: "GO_FORWARD" });
8202
- }), []);
8205
+ }), [beginProgrammaticNavigation, state2.numPages, state2.pageNumber]);
8203
8206
  const goBackward = React50.useCallback(() => __async(null, null, function* () {
8207
+ beginProgrammaticNavigation(Math.max(1, state2.pageNumber - 1));
8204
8208
  dispatch({ type: "GO_BACKWARD" });
8205
- }), []);
8209
+ }), [beginProgrammaticNavigation, state2.pageNumber]);
8206
8210
  const setScroll = React50.useCallback(
8207
8211
  (val) => __async(null, null, function* () {
8208
8212
  const isScrolling = val === "scrolling";
@@ -8228,35 +8232,40 @@ function usePdfReader(args) {
8228
8232
  const goToPage = React50.useCallback((href) => __async(null, null, function* () {
8229
8233
  dispatch({ type: "GO_TO_HREF", href });
8230
8234
  }), []);
8231
- const goToPageNumber = React50.useCallback((page) => {
8232
- dispatch({ type: "GO_TO_PAGE", page });
8233
- }, []);
8235
+ const goToPageNumber = React50.useCallback(
8236
+ (page) => {
8237
+ beginProgrammaticNavigation(page);
8238
+ dispatch({ type: "GO_TO_PAGE", page });
8239
+ },
8240
+ [beginProgrammaticNavigation]
8241
+ );
8234
8242
  const setFitMode = React50.useCallback((mode) => {
8235
8243
  dispatch({ type: "SET_FIT_MODE", fitMode: mode });
8236
8244
  }, []);
8237
- const intersectionRatios = React50.useRef({});
8238
- const lastMostVisiblePage = React50.useRef(state2.pageNumber);
8239
8245
  const onInView = React50.useCallback(
8240
8246
  (pageNum, ratio) => {
8241
8247
  var _a2;
8242
- if (!((_a2 = state2.settings) == null ? void 0 : _a2.isScrolling)) return;
8243
- intersectionRatios.current[pageNum] = ratio;
8244
- Object.keys(intersectionRatios.current).forEach((key) => {
8245
- if (intersectionRatios.current[Number(key)] === 0) {
8246
- delete intersectionRatios.current[Number(key)];
8247
- }
8248
- });
8248
+ const currentScrollState = scrollState.current;
8249
+ if (!((_a2 = state2.settings) == null ? void 0 : _a2.isScrolling) || Date.now() - currentScrollState.lastProgrammaticNavAt < IN_VIEW_DELAY_MS)
8250
+ return;
8251
+ if (ratio <= 0) {
8252
+ currentScrollState.ratios.delete(pageNum);
8253
+ return;
8254
+ }
8255
+ currentScrollState.ratios.set(pageNum, ratio);
8256
+ let mostVisiblePage = currentScrollState.lastVisiblePage;
8249
8257
  let maxRatio = -1;
8250
- let mostVisiblePage = state2.pageNumber;
8251
- for (const [page, r] of Object.entries(intersectionRatios.current)) {
8258
+ for (const [p, r] of currentScrollState.ratios) {
8252
8259
  if (r > maxRatio) {
8253
8260
  maxRatio = r;
8254
- mostVisiblePage = Number(page);
8261
+ mostVisiblePage = p;
8255
8262
  }
8263
+ if (r > 0.8) break;
8256
8264
  }
8257
- if (mostVisiblePage !== lastMostVisiblePage.current) {
8258
- lastMostVisiblePage.current = mostVisiblePage;
8265
+ if (mostVisiblePage !== currentScrollState.lastVisiblePage) {
8266
+ currentScrollState.lastVisiblePage = mostVisiblePage;
8259
8267
  if (state2.pageNumber !== mostVisiblePage) {
8268
+ currentScrollState.isInViewUpdate = true;
8260
8269
  dispatch({ type: "PAGE_IN_VIEW", page: mostVisiblePage });
8261
8270
  }
8262
8271
  }
@@ -8321,7 +8330,7 @@ function usePdfReader(args) {
8321
8330
  tabIndex: -1,
8322
8331
  id: MAIN_CONTENT_ID,
8323
8332
  ref: containerRef,
8324
- height: pageHeight,
8333
+ height,
8325
8334
  sx: {
8326
8335
  ".react-pdf__Document": {
8327
8336
  width: "100%",
@@ -8340,7 +8349,8 @@ function usePdfReader(args) {
8340
8349
  {
8341
8350
  file: state2.resource,
8342
8351
  onLoadSuccess: onDocumentLoadSuccess,
8343
- onLoadError: onDocumentLoadError
8352
+ onLoadError: onDocumentLoadError,
8353
+ inputRef: documentContainerRef
8344
8354
  },
8345
8355
  isParsed && state2.numPages && /* @__PURE__ */ React50.createElement(React50.Fragment, null, state2.settings.isScrolling && Array.from(new Array(state2.numPages), (_, index) => {
8346
8356
  var _a2;
@@ -8355,10 +8365,11 @@ function usePdfReader(args) {
8355
8365
  scale: state2.scale,
8356
8366
  pageNumber: index + 1,
8357
8367
  onLoadSuccess: onRenderSuccess,
8358
- allowInView: !isFetching,
8368
+ allowInView: state2.rendered,
8359
8369
  onInView,
8360
8370
  fitMode: state2.fitMode,
8361
- rotate: (_a2 = state2.rotation) != null ? _a2 : 0
8371
+ rotate: (_a2 = state2.rotation) != null ? _a2 : 0,
8372
+ onPageRef: setPageRef
8362
8373
  }
8363
8374
  );
8364
8375
  }), !state2.settings.isScrolling && /* @__PURE__ */ React50.createElement(
@@ -8580,6 +8591,7 @@ var src_default = WebReader;
8580
8591
  DEFAULT_SHOULD_GROW_WHEN_SCROLLING,
8581
8592
  FONT_DETAILS,
8582
8593
  HEADER_HEIGHT,
8594
+ IN_VIEW_DELAY_MS,
8583
8595
  IS_DEV,
8584
8596
  LOCAL_STORAGE_LOCATIONS_KEY,
8585
8597
  LOCAL_STORAGE_SETTINGS_KEY,