@file-viewer/renderer-pdf 2.1.27 → 2.1.29

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/pdf.js CHANGED
@@ -1,15 +1,14 @@
1
1
  import { getDocument, GlobalWorkerOptions, PDFWorker as PdfJsWorker, PixelsPerInch, } from 'pdfjs-dist/legacy/build/pdf.mjs';
2
2
  import { EventBus, GenericL10n, PDFFindController, PDFLinkService, PDFViewer, } from 'pdfjs-dist/legacy/web/pdf_viewer.mjs';
3
3
  import { registerFileViewerSearchProvider, registerFileViewerZoomProvider, unregisterFileViewerSearchProvider, unregisterFileViewerZoomProvider, registerFileViewerViewStateProvider, unregisterFileViewerViewStateProvider, createFileViewerZoomChangeEmitter, createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, buildPrintPageStyle, formatCssPixels, DEFAULT_PDF_RANGE_CHUNK_SIZE, resolveFileViewerLocale, resolveFileViewerFitScale, } from '@file-viewer/core';
4
- import { DEFAULT_FILE_VIEWER_PDF_WORKER_PATH, resolveFileViewerPdfAssetUrls, } from '@file-viewer/core/assets';
4
+ import { DEFAULT_FILE_VIEWER_PDF_WORKER_PATH, resolveFileViewerPdfAssetUrls, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
5
5
  import { pdfViewerStyle } from './pdfStyles.js';
6
6
  import { collectMalformedIdentityFontNames, createPdfCjkFontFallbackManager, detectMalformedIdentityCjkFontFamilies, } from './pdfFontFallback.js';
7
+ import { PDF_FIT_HORIZONTAL_PADDING, PDF_PAGE_BORDER_WIDTH, resolvePdfFitViewportSize, } from './pdfFit.js';
7
8
  export const DEFAULT_FILE_VIEWER_PDF_WORKER_URL = DEFAULT_FILE_VIEWER_PDF_WORKER_PATH;
8
9
  const MIN_SCALE = 0.2;
9
10
  const MAX_SCALE = 3;
10
11
  const SCALE_STEP = 0.1;
11
- const FIT_HORIZONTAL_PADDING = 28;
12
- const PAGE_BORDER_WIDTH = 18;
13
12
  const PDF_EXPORT_MAX_PAGE_PIXELS = 8000000;
14
13
  const PDF_WORKER_PROBE_TIMEOUT_MS = 1200;
15
14
  const PDF_JS_DESTROY_CONSOLE_SUPPRESSION_MS = 1500;
@@ -254,50 +253,6 @@ const installBundledPdfFakeWorker = async () => {
254
253
  const resolvePdfWorkerUrl = (options, documentBaseUrl) => {
255
254
  return resolveFileViewerPdfAssetUrls(options, documentBaseUrl).workerUrl;
256
255
  };
257
- const readBundlerPublicBaseUrl = () => {
258
- var _a;
259
- try {
260
- const value = (_a = import.meta.env) === null || _a === void 0 ? void 0 : _a.BASE_URL;
261
- return typeof value === 'string' ? value.trim() : '';
262
- }
263
- catch {
264
- return '';
265
- }
266
- };
267
- const resolvePdfRuntimeAssetBaseUrl = (documentRef) => {
268
- const documentBaseUrl = documentRef.baseURI || documentRef.URL || 'file:///';
269
- const bundlerBaseUrl = readBundlerPublicBaseUrl();
270
- if (bundlerBaseUrl && bundlerBaseUrl !== '.' && bundlerBaseUrl !== './') {
271
- try {
272
- return new URL(bundlerBaseUrl.endsWith('/') ? bundlerBaseUrl : `${bundlerBaseUrl}/`, documentBaseUrl).href;
273
- }
274
- catch {
275
- // Continue with DOM-based public-path detection.
276
- }
277
- }
278
- // An explicit <base> is authoritative and already reflected by baseURI.
279
- if (documentRef.querySelector('base[href]')) {
280
- return documentBaseUrl;
281
- }
282
- // Entry scripts remain under the public deployment base when an SPA route
283
- // changes document.baseURI. This covers Vite and common UMI/Webpack layouts.
284
- for (const script of Array.from(documentRef.querySelectorAll('script[src]'))) {
285
- try {
286
- const scriptUrl = new URL(script.src || script.getAttribute('src') || '', documentBaseUrl);
287
- const assetDirectory = scriptUrl.pathname.match(/^(.*\/)(?:assets|static)\/[^/]+$/i);
288
- if (assetDirectory) {
289
- return new URL(assetDirectory[1], scriptUrl.origin).href;
290
- }
291
- if (/\/(?:umi|main|index)(?:[.-][^/]*)?\.(?:m?js)$/i.test(scriptUrl.pathname)) {
292
- return new URL('./', scriptUrl).href;
293
- }
294
- }
295
- catch {
296
- // Ignore unrelated or malformed script URLs.
297
- }
298
- }
299
- return documentBaseUrl;
300
- };
301
256
  const buildOutlineItems = (items, prefix = 'outline', getFallbackTitle = index => `Outline ${index + 1}`) => items.map((item, index) => {
302
257
  const id = `${prefix}-${index}`;
303
258
  const children = Array.isArray(item.items)
@@ -321,7 +276,7 @@ export default async function renderPdf(buffer, target, context) {
321
276
  throw new Error(t('pdf.error.browserWindow'));
322
277
  }
323
278
  const options = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.pdf;
324
- const pdfRuntimeAssetBaseUrl = resolvePdfRuntimeAssetBaseUrl(documentRef);
279
+ const pdfRuntimeAssetBaseUrl = resolveFileViewerRuntimeAssetBaseUrl(documentRef);
325
280
  const cjkFontFallbackEnabled = (options === null || options === void 0 ? void 0 : options.cjkFontFallback) !== false;
326
281
  const identityFontRepairEnabled = (options === null || options === void 0 ? void 0 : options.identityFontRepair) !== false;
327
282
  const fontInspectionEnabled = cjkFontFallbackEnabled || identityFontRepairEnabled;
@@ -359,7 +314,9 @@ export default async function renderPdf(buffer, target, context) {
359
314
  let activeViewStateApplyVersion = 0;
360
315
  let pendingInitialViewState = initialViewState;
361
316
  let pendingFitRequest = null;
317
+ let activeFitRequest = null;
362
318
  let suppressScrollEventUntil = 0;
319
+ let userScrollIntentUntil = 0;
363
320
  let scrollStateFrame = 0;
364
321
  let pdfSearchState = createPdfSearchState();
365
322
  let pdfMatchesCount = { current: 0, total: 0 };
@@ -937,7 +894,7 @@ export default async function renderPdf(buffer, target, context) {
937
894
  label: scaleText(),
938
895
  canZoomIn: loadStatus === 'ready' && !!pdfContext.viewer && canZoomIn(),
939
896
  canZoomOut: loadStatus === 'ready' && !!pdfContext.viewer && canZoomOut(),
940
- canReset: loadStatus === 'ready' && !!pdfContext.viewer && !autoFitWidth,
897
+ canReset: loadStatus === 'ready' && !!pdfContext.viewer && Math.abs(currentScale - 1) > 0.001,
941
898
  minScale: MIN_SCALE,
942
899
  maxScale: MAX_SCALE,
943
900
  });
@@ -993,6 +950,21 @@ export default async function renderPdf(buffer, target, context) {
993
950
  const suppressProgrammaticScrollEvents = () => {
994
951
  suppressScrollEventUntil = Math.max(suppressScrollEventUntil, Date.now() + 180);
995
952
  };
953
+ const markFitInteraction = (source) => {
954
+ if (source !== 'user' && source !== 'api') {
955
+ return;
956
+ }
957
+ if ((activeFitRequest === null || activeFitRequest === void 0 ? void 0 : activeFitRequest.resize) === 'always') {
958
+ return;
959
+ }
960
+ autoFitWidth = false;
961
+ activeFitRequest = null;
962
+ };
963
+ const recordUserScrollIntent = () => {
964
+ userScrollIntentUntil = Date.now() + 750;
965
+ suppressScrollEventUntil = 0;
966
+ markFitInteraction('user');
967
+ };
996
968
  const restoreScrollState = (scroll, notify = true) => {
997
969
  if (!scroll) {
998
970
  return;
@@ -1020,6 +992,7 @@ export default async function renderPdf(buffer, target, context) {
1020
992
  const source = applyOptions.source || 'api';
1021
993
  const action = applyOptions.action || 'restore';
1022
994
  const notify = applyOptions.notify !== false;
995
+ markFitInteraction(source);
1023
996
  const applyVersion = ++viewStateApplyVersion;
1024
997
  activeViewStateApplyVersion = applyVersion;
1025
998
  suppressProgrammaticScrollEvents();
@@ -1078,7 +1051,11 @@ export default async function renderPdf(buffer, target, context) {
1078
1051
  }
1079
1052
  scrollStateFrame = targetWindow.requestAnimationFrame(() => {
1080
1053
  scrollStateFrame = 0;
1081
- emitViewStateChange('scroll', 'user');
1054
+ const source = Date.now() <= userScrollIntentUntil
1055
+ ? 'user'
1056
+ : 'viewer';
1057
+ markFitInteraction(source);
1058
+ emitViewStateChange('scroll', source);
1082
1059
  });
1083
1060
  };
1084
1061
  const setScale = (scale, action = 'zoom-change', source = 'viewer', notifyViewState = true) => {
@@ -1126,13 +1103,15 @@ export default async function renderPdf(buffer, target, context) {
1126
1103
  const getFitWidthScale = (pdfViewer) => {
1127
1104
  const pageWidth = getPageWidthAtScaleOne(pdfViewer);
1128
1105
  const containerWidth = container.clientWidth || targetWindow.innerWidth;
1129
- const availableWidth = Math.max(containerWidth - FIT_HORIZONTAL_PADDING - PAGE_BORDER_WIDTH, 96);
1106
+ const availableWidth = Math.max(containerWidth - PDF_FIT_HORIZONTAL_PADDING - PDF_PAGE_BORDER_WIDTH, 96);
1130
1107
  return pageWidth ? clampScale(availableWidth / pageWidth) : 1;
1131
1108
  };
1132
1109
  const fitToWidth = (source = 'user', notifyViewState = true) => {
1133
1110
  if (!pdfContext.viewer) {
1134
1111
  return;
1135
1112
  }
1113
+ userScrollIntentUntil = 0;
1114
+ suppressProgrammaticScrollEvents();
1136
1115
  autoFitWidth = true;
1137
1116
  setScale(getFitWidthScale(pdfContext.viewer), 'zoom-reset', source, notifyViewState);
1138
1117
  void waitForPaint(targetWindow).then(() => {
@@ -1142,6 +1121,8 @@ export default async function renderPdf(buffer, target, context) {
1142
1121
  };
1143
1122
  const applyPdfFit = async (request) => {
1144
1123
  var _a, _b, _c;
1124
+ userScrollIntentUntil = 0;
1125
+ activeFitRequest = { ...request };
1145
1126
  if (!pdfContext.viewer || loadStatus !== 'ready') {
1146
1127
  pendingFitRequest = request;
1147
1128
  return {
@@ -1155,13 +1136,20 @@ export default async function renderPdf(buffer, target, context) {
1155
1136
  }
1156
1137
  const pageSize = getPageSizeAtScaleOne(pdfContext.viewer);
1157
1138
  const mode = request.mode === 'auto' ? 'width' : request.mode;
1139
+ const fitViewport = resolvePdfFitViewportSize({
1140
+ containerWidth: container.clientWidth,
1141
+ containerHeight: container.clientHeight,
1142
+ fallbackWidth: targetWindow.innerWidth,
1143
+ fallbackHeight: targetWindow.innerHeight,
1144
+ request,
1145
+ });
1158
1146
  const scale = resolveFileViewerFitScale({
1159
1147
  mode,
1160
- viewportWidth: Math.max(96, (request.viewportWidth || container.clientWidth || targetWindow.innerWidth) -
1161
- FIT_HORIZONTAL_PADDING -
1162
- PAGE_BORDER_WIDTH),
1163
- viewportHeight: Math.max(96, (container.clientHeight || request.viewportHeight || targetWindow.innerHeight) -
1164
- PAGE_BORDER_WIDTH),
1148
+ // The core request measures the whole viewer root. PDF's scroll
1149
+ // container is the actual visible document area after the navigation
1150
+ // pane, so prefer it whenever it has been laid out.
1151
+ viewportWidth: fitViewport.width,
1152
+ viewportHeight: fitViewport.height,
1165
1153
  contentWidth: pageSize.width,
1166
1154
  contentHeight: pageSize.height,
1167
1155
  currentScale,
@@ -1178,9 +1166,17 @@ export default async function renderPdf(buffer, target, context) {
1178
1166
  provider: 'view-state',
1179
1167
  };
1180
1168
  }
1169
+ suppressProgrammaticScrollEvents();
1181
1170
  autoFitWidth = request.mode === 'auto' || request.mode === 'width';
1182
- setScale(scale, 'fit', request.source);
1171
+ if (Math.abs(scale - currentScale) > 0.001) {
1172
+ setScale(scale, 'fit', request.source);
1173
+ }
1174
+ else {
1175
+ pdfContext.viewer.update();
1176
+ syncUi();
1177
+ }
1183
1178
  await waitForPaint(targetWindow);
1179
+ suppressProgrammaticScrollEvents();
1184
1180
  (_c = pdfContext.viewer) === null || _c === void 0 ? void 0 : _c.update();
1185
1181
  const state = getPdfViewState();
1186
1182
  return {
@@ -1193,22 +1189,49 @@ export default async function renderPdf(buffer, target, context) {
1193
1189
  state,
1194
1190
  };
1195
1191
  };
1196
- const scheduleFitToWidth = () => {
1197
- if (!autoFitWidth || !pdfContext.viewer) {
1192
+ const scheduleFitAfterResize = () => {
1193
+ if (!pdfContext.viewer) {
1194
+ return;
1195
+ }
1196
+ if ((activeFitRequest === null || activeFitRequest === void 0 ? void 0 : activeFitRequest.resize) === 'initial') {
1197
+ return;
1198
+ }
1199
+ if (!activeFitRequest && !autoFitWidth) {
1198
1200
  return;
1199
1201
  }
1200
1202
  targetWindow.cancelAnimationFrame(fitFrame);
1201
- fitFrame = targetWindow.requestAnimationFrame(() => fitToWidth('viewer'));
1203
+ fitFrame = targetWindow.requestAnimationFrame(() => {
1204
+ if (activeFitRequest) {
1205
+ void applyPdfFit({ ...activeFitRequest, source: 'viewer' });
1206
+ return;
1207
+ }
1208
+ fitToWidth('viewer');
1209
+ });
1202
1210
  };
1203
1211
  const zoomIn = (source = 'user') => {
1204
- autoFitWidth = false;
1212
+ markFitInteraction(source);
1205
1213
  setScale(currentScale + SCALE_STEP, 'zoom-in', source);
1206
1214
  };
1207
1215
  const zoomOut = (source = 'user') => {
1208
- autoFitWidth = false;
1216
+ markFitInteraction(source);
1209
1217
  setScale(currentScale - SCALE_STEP, 'zoom-out', source);
1210
1218
  };
1219
+ const reapplyFitAfterLayout = (source, notifyViewState = true) => {
1220
+ if (activeFitRequest) {
1221
+ if (activeFitRequest.resize === 'initial') {
1222
+ return false;
1223
+ }
1224
+ void applyPdfFit({ ...activeFitRequest, source });
1225
+ return true;
1226
+ }
1227
+ if (autoFitWidth) {
1228
+ fitToWidth(source, notifyViewState);
1229
+ return true;
1230
+ }
1231
+ return false;
1232
+ };
1211
1233
  const applyRotation = (rotation, action = 'rotation-change', source = 'viewer', notifyViewState = true) => {
1234
+ markFitInteraction(source);
1212
1235
  const normalized = normalizeRotation(rotation);
1213
1236
  currentRotation = normalized;
1214
1237
  pdfThumbnails.clear();
@@ -1220,8 +1243,7 @@ export default async function renderPdf(buffer, target, context) {
1220
1243
  pdfContext.viewer.pagesRotation = normalized;
1221
1244
  void waitForPaint(targetWindow).then(() => {
1222
1245
  var _a;
1223
- if (autoFitWidth) {
1224
- fitToWidth(source, notifyViewState);
1246
+ if (reapplyFitAfterLayout(source, notifyViewState)) {
1225
1247
  if (notifyViewState) {
1226
1248
  emitViewStateChange(action, source);
1227
1249
  }
@@ -1247,6 +1269,7 @@ export default async function renderPdf(buffer, target, context) {
1247
1269
  if (!pdfContext.viewer || !pageCount) {
1248
1270
  return;
1249
1271
  }
1272
+ markFitInteraction(source);
1250
1273
  const nextPage = Math.min(pageCount, Math.max(1, pageNumber));
1251
1274
  runWithStableHorizontalScroll(() => {
1252
1275
  pdfContext.viewer.currentPageNumber = nextPage;
@@ -1261,12 +1284,12 @@ export default async function renderPdf(buffer, target, context) {
1261
1284
  if (!navigationEnabled) {
1262
1285
  return;
1263
1286
  }
1287
+ markFitInteraction(source);
1264
1288
  navVisible = !navVisible;
1265
1289
  syncUi();
1266
1290
  void waitForPaint(targetWindow).then(() => {
1267
1291
  var _a;
1268
- if (autoFitWidth) {
1269
- fitToWidth(source, notifyViewState);
1292
+ if (reapplyFitAfterLayout(source, notifyViewState)) {
1270
1293
  return;
1271
1294
  }
1272
1295
  (_a = pdfContext.viewer) === null || _a === void 0 ? void 0 : _a.update();
@@ -1276,6 +1299,7 @@ export default async function renderPdf(buffer, target, context) {
1276
1299
  }
1277
1300
  };
1278
1301
  const setNavMode = (mode, source = 'user', notifyViewState = true) => {
1302
+ markFitInteraction(source);
1279
1303
  navMode = mode;
1280
1304
  syncUi();
1281
1305
  if (notifyViewState) {
@@ -1403,7 +1427,7 @@ export default async function renderPdf(buffer, target, context) {
1403
1427
  `width:${formatCssPixels(pageWidth)}`,
1404
1428
  `height:${formatCssPixels(pageHeight)}`,
1405
1429
  ].join(';');
1406
- pagesHtml.push(`<section class="pdf-export-page viewer-print-page" style="${pageStyle}" aria-label="${escapeAttribute(pageTitle)}"><img src="${canvas.toDataURL('image/png')}" alt="${escapeAttribute(pageTitle)}" /></section>`);
1430
+ pagesHtml.push(`<section class="pdf-export-page viewer-print-page" data-viewer-print-page-index="${pageNumber - 1}" style="${pageStyle}" aria-label="${escapeAttribute(pageTitle)}"><img src="${canvas.toDataURL('image/png')}" alt="${escapeAttribute(pageTitle)}" /></section>`);
1407
1431
  canvas.width = 0;
1408
1432
  canvas.height = 0;
1409
1433
  (_b = (_a = page).cleanup) === null || _b === void 0 ? void 0 : _b.call(_a);
@@ -1458,7 +1482,6 @@ export default async function renderPdf(buffer, target, context) {
1458
1482
  var _a;
1459
1483
  applyRotation(currentRotation, 'rotation-change', 'viewer', false);
1460
1484
  loadStatus = 'ready';
1461
- fitToWidth('viewer', false);
1462
1485
  scheduleLegacyPageDimensionPatch();
1463
1486
  syncUi();
1464
1487
  (_a = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _a === void 0 ? void 0 : _a.call(context);
@@ -1477,6 +1500,7 @@ export default async function renderPdf(buffer, target, context) {
1477
1500
  void applyPdfFit(fitRequest);
1478
1501
  }
1479
1502
  else {
1503
+ fitToWidth('viewer', false);
1480
1504
  emitViewStateChange('init', 'viewer');
1481
1505
  }
1482
1506
  }
@@ -1657,6 +1681,7 @@ export default async function renderPdf(buffer, target, context) {
1657
1681
  }
1658
1682
  (_c = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _c === void 0 ? void 0 : _c.call(context, {
1659
1683
  includeDocumentStyles: false,
1684
+ getPrintMaskPages: () => Array.from(root.querySelectorAll('.pdfViewer .page')),
1660
1685
  printStyle: buildPdfPrintStyle,
1661
1686
  toHtml: renderPdfPagesForExport,
1662
1687
  });
@@ -1699,11 +1724,12 @@ export default async function renderPdf(buffer, target, context) {
1699
1724
  return getPdfZoomState();
1700
1725
  },
1701
1726
  resetZoom: () => {
1702
- fitToWidth('api');
1727
+ markFitInteraction('api');
1728
+ setScale(1, 'zoom-reset', 'api');
1703
1729
  return getPdfZoomState();
1704
1730
  },
1705
1731
  setZoom: scale => {
1706
- autoFitWidth = false;
1732
+ markFitInteraction('api');
1707
1733
  setScale(scale, 'zoom-change', 'api');
1708
1734
  return getPdfZoomState();
1709
1735
  },
@@ -1722,14 +1748,21 @@ export default async function renderPdf(buffer, target, context) {
1722
1748
  nextPageButton.addEventListener('click', () => goToPage(currentPage + 1, 'page-step', 'user'));
1723
1749
  zoomOutButton.addEventListener('click', () => zoomOut('user'));
1724
1750
  zoomInButton.addEventListener('click', () => zoomIn('user'));
1725
- scaleButton.addEventListener('click', () => fitToWidth('user'));
1751
+ scaleButton.addEventListener('click', () => {
1752
+ activeFitRequest = null;
1753
+ fitToWidth('user');
1754
+ });
1726
1755
  rotateLeftButton.addEventListener('click', () => applyRotation(currentRotation - 90, 'rotate-left', 'user'));
1727
1756
  rotateRightButton.addEventListener('click', () => applyRotation(currentRotation + 90, 'rotate-right', 'user'));
1728
1757
  pagesTab.addEventListener('click', () => setNavMode('pages', 'user'));
1729
1758
  outlineTab.addEventListener('click', () => setNavMode('outline', 'user'));
1759
+ container.addEventListener('wheel', recordUserScrollIntent, { passive: true });
1760
+ container.addEventListener('touchstart', recordUserScrollIntent, { passive: true });
1761
+ container.addEventListener('pointerdown', recordUserScrollIntent, { passive: true });
1762
+ container.addEventListener('keydown', recordUserScrollIntent);
1730
1763
  container.addEventListener('scroll', scheduleScrollViewStateChange, { passive: true });
1731
1764
  if (targetWindow.ResizeObserver) {
1732
- resizeObserver = new targetWindow.ResizeObserver(() => scheduleFitToWidth());
1765
+ resizeObserver = new targetWindow.ResizeObserver(() => scheduleFitAfterResize());
1733
1766
  resizeObserver.observe(container);
1734
1767
  }
1735
1768
  syncUi();
@@ -0,0 +1,20 @@
1
+ import type { FileViewerFitRequest } from '@file-viewer/core';
2
+ export declare const PDF_FIT_MIN_VIEWPORT_SIZE = 96;
3
+ export declare const PDF_FIT_HORIZONTAL_PADDING = 28;
4
+ export declare const PDF_PAGE_BORDER_WIDTH = 18;
5
+ export interface ResolvePdfFitViewportSizeInput {
6
+ containerWidth: number;
7
+ containerHeight: number;
8
+ fallbackWidth: number;
9
+ fallbackHeight: number;
10
+ request: Pick<FileViewerFitRequest, 'viewportWidth' | 'viewportHeight' | 'padding'>;
11
+ }
12
+ /**
13
+ * Resolves the PDF page viewport after the navigation pane has been laid out.
14
+ * Core request dimensions already exclude fit.padding; live container and
15
+ * window fallback dimensions do not, so only those branches subtract it.
16
+ */
17
+ export declare const resolvePdfFitViewportSize: ({ containerWidth, containerHeight, fallbackWidth, fallbackHeight, request, }: ResolvePdfFitViewportSizeInput) => {
18
+ width: number;
19
+ height: number;
20
+ };
package/dist/pdfFit.js ADDED
@@ -0,0 +1,26 @@
1
+ export const PDF_FIT_MIN_VIEWPORT_SIZE = 96;
2
+ export const PDF_FIT_HORIZONTAL_PADDING = 28;
3
+ export const PDF_PAGE_BORDER_WIDTH = 18;
4
+ const normalizePadding = (padding) => (Number.isFinite(padding) && Number(padding) > 0 ? Number(padding) : 0);
5
+ /**
6
+ * Resolves the PDF page viewport after the navigation pane has been laid out.
7
+ * Core request dimensions already exclude fit.padding; live container and
8
+ * window fallback dimensions do not, so only those branches subtract it.
9
+ */
10
+ export const resolvePdfFitViewportSize = ({ containerWidth, containerHeight, fallbackWidth, fallbackHeight, request, }) => {
11
+ const padding = normalizePadding(request.padding);
12
+ const requestWidth = Number(request.viewportWidth) || 0;
13
+ const requestHeight = Number(request.viewportHeight) || 0;
14
+ const hasContainerWidth = containerWidth > 0;
15
+ const hasContainerHeight = containerHeight > 0;
16
+ const width = hasContainerWidth
17
+ ? containerWidth - padding * 2
18
+ : requestWidth || fallbackWidth - padding * 2;
19
+ const height = hasContainerHeight
20
+ ? containerHeight - padding * 2
21
+ : requestHeight || fallbackHeight - padding * 2;
22
+ return {
23
+ width: Math.max(PDF_FIT_MIN_VIEWPORT_SIZE, width - PDF_FIT_HORIZONTAL_PADDING - PDF_PAGE_BORDER_WIDTH),
24
+ height: Math.max(PDF_FIT_MIN_VIEWPORT_SIZE, height - PDF_PAGE_BORDER_WIDTH),
25
+ };
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/renderer-pdf",
3
- "version": "2.1.27",
3
+ "version": "2.1.29",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone PDF renderer plugin for Flyfish File Viewer powered by PDF.js.",
@@ -54,7 +54,7 @@
54
54
  "LICENSE"
55
55
  ],
56
56
  "dependencies": {
57
- "@file-viewer/core": "2.1.27",
57
+ "@file-viewer/core": "2.1.29",
58
58
  "@fontsource-variable/noto-sans-sc": "5.2.10",
59
59
  "pdf-lib": "1.17.1",
60
60
  "pdfjs-dist": "5.4.624"