@file-viewer/core 2.1.22 → 2.1.24

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/assets.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/assets';
package/assets.js ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/assets.js';
package/browser.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/browser';
package/browser.js ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/browser.js';
@@ -41,7 +41,7 @@ const sanitizeJsonValue = (value) => {
41
41
  return Object.keys(output).length ? output : undefined;
42
42
  };
43
43
  const stripExecutionOnlyOptions = (value) => {
44
- const { beforeOperation: _beforeOperation, hooks: _hooks, preset: _preset, presets: _presets, renderers: _renderers, rendererMode: _rendererMode, branding: _branding, ...rest } = value;
44
+ const { beforeOperation: _beforeOperation, hooks: _hooks, preset: _preset, presets: _presets, renderers: _renderers, rendererMode: _rendererMode, ...rest } = value;
45
45
  if (isRecord(rest.toolbar)) {
46
46
  const { beforeOperation: _toolbarBeforeOperation, beforeDownload: _beforeDownload, beforePrint: _beforePrint, beforeExportHtml: _beforeExportHtml, ...toolbar } = rest.toolbar;
47
47
  rest.toolbar = toolbar;
@@ -2,7 +2,7 @@ export type FileViewerSourceKind = 'file' | 'url' | 'buffer' | 'empty';
2
2
  export type FileViewerThemeMode = 'light' | 'dark' | 'system';
3
3
  export type FileViewerLocale = 'auto' | 'zh-CN' | 'en-US' | (string & {});
4
4
  export type FileViewerStyleIsolation = 'auto' | 'shadow' | 'scoped' | 'none';
5
- export type FileViewerMessageKey = 'toolbar.zoomGroup' | 'toolbar.zoomOut' | 'toolbar.zoomIn' | 'toolbar.zoomReset' | 'toolbar.download' | 'toolbar.downloadTitle' | 'toolbar.print' | 'toolbar.printTitle' | 'toolbar.exportHtml' | 'toolbar.exportHtmlTitle' | 'toolbar.search' | 'toolbar.searchPlaceholder' | 'toolbar.searchPrevious' | 'toolbar.searchNext' | 'toolbar.searchClear' | 'state.ready.title' | 'state.ready.message' | 'state.empty.title' | 'state.empty.message' | 'state.unsupported.install.title' | 'state.unsupported.install.message' | 'state.unsupported.install.description' | 'state.unsupported.title' | 'state.unsupported.message' | 'state.unsupported.description' | 'state.error.title' | 'preview.downloading' | 'preview.streamingPdf' | 'preview.reading' | 'error.download' | 'error.print' | 'error.exportHtml' | 'error.noDownloadSource' | 'error.noExportContent' | 'error.printUnavailable' | 'error.printWindowBlocked' | 'error.remoteDownload' | 'error.localRead' | 'error.load' | 'error.stream' | 'error.beforeOperation' | 'error.unknown' | 'error.blobUnavailable' | 'error.sourceUnsupported' | 'error.fileReadArrayBuffer' | 'error.fileReadDataUrl' | 'error.fileReadText' | 'error.imageDataUrlRead' | 'operation.download' | 'operation.print' | 'operation.exportHtml' | 'operation.zoomIn' | 'operation.zoomOut' | 'operation.zoomReset' | 'pdf.toolbar.toggleNavigation' | 'pdf.toolbar.previousPage' | 'pdf.toolbar.nextPage' | 'pdf.toolbar.fitWidth' | 'pdf.toolbar.zoomOut' | 'pdf.toolbar.zoomIn' | 'pdf.toolbar.rotateLeft' | 'pdf.toolbar.rotateRight' | 'pdf.nav.typeLabel' | 'pdf.nav.pagesTab' | 'pdf.nav.outlineTab' | 'pdf.nav.pagesTitle' | 'pdf.nav.outlineTitle' | 'pdf.nav.pageCount' | 'pdf.nav.itemCount' | 'pdf.nav.pageLabel' | 'pdf.nav.outlineEmpty' | 'pdf.nav.outlineFallbackTitle' | 'pdf.thumbnail.alt' | 'pdf.state.loading' | 'pdf.error.browserWindow' | 'pdf.error.missingSource' | 'pdf.error.loadFailed' | 'pdf.error.notLoaded' | 'pdf.error.unloaded' | 'pdf.error.canvasUnavailable' | 'pdf.export.pageTitle' | 'spreadsheet.loading.kicker' | 'spreadsheet.loading.title' | 'spreadsheet.loading.hint' | 'spreadsheet.loading.streaming' | 'spreadsheet.tabs.ariaLabel' | 'spreadsheet.state.parsingWorkbook' | 'spreadsheet.state.preparingSheet' | 'spreadsheet.state.preparingSheetNamed' | 'spreadsheet.state.cachedRows' | 'spreadsheet.state.rows' | 'spreadsheet.state.rowsAndColumns' | 'spreadsheet.error.parseFailed' | 'spreadsheet.error.workerFailed' | 'word.error.invalidDocx' | 'word.error.missingOdfContent' | 'word.error.odfXmlParseFailed' | 'word.title.rtf' | 'word.title.openDocumentPresentation' | 'word.title.openDocumentText' | 'word.page.fallback' | 'word.page.empty' | 'word.body' | 'word.body.empty' | 'ofd.state.loading' | 'ofd.error.empty' | 'ofd.error.parseFailed' | 'presentation.state.loading' | 'presentation.error.title' | 'presentation.error.parseFailed' | 'archive.error.nestedUnsupported' | 'archive.loading.readingDirectory' | 'archive.loading.readingDirectoryHint' | 'archive.search.placeholder' | 'archive.sidebar.hide' | 'archive.sidebar.show' | 'archive.preview.title' | 'archive.preview.chooseFile' | 'archive.preview.downloadFile' | 'archive.error.title' | 'archive.stats.summary' | 'archive.warning.encrypted' | 'archive.password.title' | 'archive.password.description' | 'archive.password.placeholder' | 'archive.password.invalid' | 'archive.password.required' | 'archive.password.cancel' | 'archive.password.confirm' | 'archive.error.passwordRequired' | 'archive.error.encryptedRequiresWorker' | 'archive.empty.title' | 'archive.empty.message' | 'archive.loading.initializingCandidate' | 'archive.loading.initializingCandidateHint' | 'archive.error.candidateInitTimeout' | 'archive.error.encryptedCheckTimeout' | 'archive.loading.directoryReadyHint' | 'archive.error.candidateReadTimeout' | 'archive.loading.workerFallback' | 'archive.loading.workerFallbackHint' | 'archive.notice.workerFallback' | 'archive.error.tooLarge' | 'archive.loading.initializingWorker' | 'archive.loading.initializingWorkerHint' | 'archive.error.workerInitFailed' | 'archive.error.workerUnsupported' | 'archive.error.indexedDbUnavailable' | 'archive.error.entryTooLarge' | 'archive.loading.extracting' | 'archive.loading.rendering' | 'archive.loading.exporting' | 'media.audio.title' | 'media.audio.description' | 'media.audio.unsupported' | 'media.video.title' | 'media.video.unsupported' | 'media.video.hlsHint' | 'media.midi.title' | 'media.midi.loading' | 'media.midi.trackHeader' | 'media.midi.instrumentHeader' | 'media.midi.channelHeader' | 'media.midi.noteCountHeader' | 'media.midi.durationHeader' | 'media.midi.durationStat' | 'media.midi.trackStat' | 'media.midi.noteStat' | 'media.midi.parseFailed' | 'email.mbox.subject' | 'email.mbox.summary' | 'email.error.title' | 'email.meta.from' | 'email.meta.to' | 'email.meta.cc' | 'email.meta.date' | 'email.tabs.text' | 'email.tabs.headers' | 'email.attachments.title' | 'email.attachments.empty' | 'email.attachments.download' | 'email.attachments.opening' | 'email.attachments.nestedUnavailable' | 'email.loading.parsing' | 'data.font.sample' | 'data.error.fontFaceUnsupported' | 'data.title.font' | 'data.title.sqlite' | 'data.title.parquet' | 'data.title.avro' | 'data.title.wasm' | 'data.title.eps' | 'data.title.ai' | 'data.title.webarchive' | 'data.title.summary' | 'data.label.format' | 'data.label.size' | 'data.label.rendering' | 'data.label.objects' | 'data.label.sampleTable' | 'data.label.rows' | 'data.label.columns' | 'data.label.sampleRows' | 'data.label.imports' | 'data.label.exports' | 'data.label.magic' | 'data.label.note' | 'data.label.container' | 'data.value.schemaRead' | 'data.value.schemaUnread' | 'data.note.aiSummary' | 'data.note.postscriptSummary' | 'data.note.webarchive' | 'data.image.alt' | 'psd.title' | 'psd.action.fit' | 'psd.action.showAll' | 'psd.action.hideAll' | 'psd.layers.title' | 'psd.layers.redrawable' | 'psd.layers.empty' | 'psd.layers.hidden' | 'drawing.error.viewerLoadFailed' | 'drawing.error.excalidrawEmpty' | 'drawing.error.excalidrawTimeout' | 'drawing.error.drawioParseFailed' | 'drawing.error.drawioNoModel' | 'drawing.error.drawioNoElements' | 'drawing.error.viewerInitFailed' | 'drawing.error.drawioTimeout' | 'drawing.error.svgParseFailed' | 'drawing.error.plantumlRenderFailed' | 'drawing.title.excalidraw' | 'drawing.title.mermaid' | 'drawing.title.plantuml' | 'drawing.title.drawio' | 'drawing.toolbar.zoomOut' | 'drawing.toolbar.zoomIn' | 'drawing.toolbar.fit' | 'drawing.toolbar.fitWidth' | 'drawing.state.loading' | 'text.code.loadingHighlight' | 'ebook.toc' | 'ebook.reading' | 'ebook.itemCount' | 'epub.title' | 'epub.previousPage' | 'epub.nextPage' | 'epub.loading' | 'epub.chapterFallback' | 'epub.renderIncomplete' | 'umd.title' | 'umd.previousChapter' | 'umd.nextChapter' | 'umd.loading' | 'umd.emptyContent' | 'umd.chapterFallback' | 'umd.galleryFallback' | 'umd.warningBodyTooShort' | 'umd.error.unexpectedEnd' | 'umd.error.invalidFile' | 'typst.summaryRenderer' | 'typst.pageSummary.empty' | 'typst.pageSummary.ready' | 'typst.status.compiling' | 'typst.status.failed' | 'typst.status.rendered' | 'typst.loading.title' | 'typst.loading.hint' | 'typst.error.title' | 'typst.error.timeout' | 'typst.error.timeoutHint' | 'typst.error.assetHint' | 'typst.error.svgParseFailed' | 'typst.error.wasmLoadFailed' | 'xmind.toolbar.zoomOut' | 'xmind.toolbar.zoomIn' | 'xmind.toolbar.fit' | 'xmind.toolbar.fitTitle' | 'xmind.state.loading' | 'xmind.stats.nodes' | 'xmind.stats.depth' | 'xmind.stats.theme' | 'xmind.stats.template' | 'xmind.badge.paused' | 'xmind.badge.collapsed' | 'xmind.badge.floating' | 'xmind.badge.summary' | 'xmind.badge.callout' | 'xmind.imageResource' | 'xmind.error.unrecognized' | 'xmind.error.noCanvas' | 'cad.toolbar.fit' | 'cad.toolbar.zoomOut' | 'cad.toolbar.zoomIn' | 'cad.layers.title' | 'cad.layers.count' | 'cad.inspector.title' | 'cad.inspector.entities' | 'cad.inspector.blocks' | 'cad.inspector.pages' | 'cad.inspector.drawn' | 'cad.state.loadingViewer' | 'cad.state.parsing' | 'cad.error.parseFailed' | 'image.alt' | 'image.lightbox.alt' | 'image.lightbox.close' | 'gitBundle.error.invalid' | 'gitBundle.error.missingPack' | 'gitBundle.notice.delta' | 'gitBundle.title.history' | 'gitBundle.title.fileTree' | 'gitBundle.file.choose' | 'gitBundle.file.noTree' | 'gitBundle.file.none' | 'gitBundle.history.empty' | 'gitBundle.toolbar.summary' | 'gitBundle.meta.bundle' | 'gitBundle.meta.refs' | 'gitBundle.meta.commits' | 'gitBundle.meta.objects' | 'gitBundle.meta.deltas' | 'gitBundle.meta.objectFormat' | 'gitBundle.meta.objectTypes' | 'geo.error.unrecognized' | 'geo.error.xmlParseFailed' | 'geo.error.unsupported' | 'geo.title' | 'geo.featureCount' | 'geo.bounds' | 'geo.geometryTypes' | 'geo.aria' | 'geo.loading' | 'geo.projection' | 'geo.engine' | 'geo.basemap' | 'geo.basemap.offline' | 'geo.basemap.custom' | 'geo.engine.maplibre' | 'geo.engine.svg' | 'geo.error.projection' | 'geo.action.fit' | 'model.toolbar.fit' | 'model.toolbar.rotate' | 'model.toolbar.wireframe' | 'model.toolbar.grid' | 'model.toolbar.axes' | 'model.state.loadingSummary' | 'model.state.loading' | 'model.state.loaded' | 'model.state.parseFailed' | 'model.summary.meshes' | 'model.summary.points' | 'model.error.daeEmpty' | 'model.error.unsupported' | 'model.error.parseFailed' | 'model.notice.signature' | 'loading.generic.label' | 'loading.generic.hint' | 'loading.word.label' | 'loading.word.hint' | 'loading.wordWorker.hint' | 'loading.sheet.label' | 'loading.sheet.hint' | 'loading.csv.label' | 'loading.csv.hint' | 'loading.presentation.label' | 'loading.presentation.hint' | 'loading.pdf.label' | 'loading.pdf.hint' | 'loading.ofd.label' | 'loading.ofd.hint' | 'loading.archive.label' | 'loading.archive.hint' | 'loading.email.label' | 'loading.email.hint' | 'loading.msg.hint' | 'loading.eda.label' | 'loading.eda.hint' | 'loading.cad.label' | 'loading.cad.hint' | 'loading.dwg.hint' | 'loading.dwf.hint' | 'loading.dwfx.hint' | 'loading.xps.hint' | 'loading.drawio.label' | 'loading.drawio.hint' | 'loading.excalidraw.label' | 'loading.excalidraw.hint' | 'loading.epub.label' | 'loading.epub.hint' | 'loading.umd.label' | 'loading.umd.hint' | 'loading.image.label' | 'loading.image.hint' | 'loading.video.label' | 'loading.video.hint' | 'loading.audio.label' | 'loading.audio.hint';
5
+ export type FileViewerMessageKey = 'toolbar.zoomGroup' | 'toolbar.zoomOut' | 'toolbar.zoomIn' | 'toolbar.zoomReset' | 'toolbar.download' | 'toolbar.downloadTitle' | 'toolbar.print' | 'toolbar.printTitle' | 'toolbar.printDirect' | 'toolbar.printMask' | 'toolbar.printMaskTitle' | 'toolbar.printMaskAdd' | 'toolbar.printMaskClear' | 'toolbar.printMaskCancel' | 'toolbar.printMaskConfirm' | 'toolbar.printMaskHint' | 'toolbar.exportHtml' | 'toolbar.exportHtmlTitle' | 'toolbar.search' | 'toolbar.searchPlaceholder' | 'toolbar.searchPrevious' | 'toolbar.searchNext' | 'toolbar.searchClear' | 'state.ready.title' | 'state.ready.message' | 'state.empty.title' | 'state.empty.message' | 'state.unsupported.install.title' | 'state.unsupported.install.message' | 'state.unsupported.install.description' | 'state.unsupported.title' | 'state.unsupported.message' | 'state.unsupported.description' | 'state.error.title' | 'preview.downloading' | 'preview.streamingPdf' | 'preview.reading' | 'error.download' | 'error.print' | 'error.exportHtml' | 'error.noDownloadSource' | 'error.noExportContent' | 'error.printUnavailable' | 'error.printWindowBlocked' | 'error.remoteDownload' | 'error.localRead' | 'error.load' | 'error.stream' | 'error.beforeOperation' | 'error.unknown' | 'error.blobUnavailable' | 'error.sourceUnsupported' | 'error.fileReadArrayBuffer' | 'error.fileReadDataUrl' | 'error.fileReadText' | 'error.imageDataUrlRead' | 'operation.download' | 'operation.print' | 'operation.exportHtml' | 'operation.zoomIn' | 'operation.zoomOut' | 'operation.zoomReset' | 'pdf.toolbar.toggleNavigation' | 'pdf.toolbar.previousPage' | 'pdf.toolbar.nextPage' | 'pdf.toolbar.fitWidth' | 'pdf.toolbar.zoomOut' | 'pdf.toolbar.zoomIn' | 'pdf.toolbar.rotateLeft' | 'pdf.toolbar.rotateRight' | 'pdf.nav.typeLabel' | 'pdf.nav.pagesTab' | 'pdf.nav.outlineTab' | 'pdf.nav.pagesTitle' | 'pdf.nav.outlineTitle' | 'pdf.nav.pageCount' | 'pdf.nav.itemCount' | 'pdf.nav.pageLabel' | 'pdf.nav.outlineEmpty' | 'pdf.nav.outlineFallbackTitle' | 'pdf.thumbnail.alt' | 'pdf.state.loading' | 'pdf.error.browserWindow' | 'pdf.error.missingSource' | 'pdf.error.loadFailed' | 'pdf.error.notLoaded' | 'pdf.error.unloaded' | 'pdf.error.canvasUnavailable' | 'pdf.export.pageTitle' | 'spreadsheet.loading.kicker' | 'spreadsheet.loading.title' | 'spreadsheet.loading.hint' | 'spreadsheet.loading.streaming' | 'spreadsheet.tabs.ariaLabel' | 'spreadsheet.state.parsingWorkbook' | 'spreadsheet.state.preparingSheet' | 'spreadsheet.state.preparingSheetNamed' | 'spreadsheet.state.cachedRows' | 'spreadsheet.state.rows' | 'spreadsheet.state.rowsAndColumns' | 'spreadsheet.error.parseFailed' | 'spreadsheet.error.workerFailed' | 'word.error.invalidDocx' | 'word.error.missingOdfContent' | 'word.error.odfXmlParseFailed' | 'word.title.rtf' | 'word.title.openDocumentPresentation' | 'word.title.openDocumentText' | 'word.page.fallback' | 'word.page.empty' | 'word.body' | 'word.body.empty' | 'ofd.state.loading' | 'ofd.error.empty' | 'ofd.error.parseFailed' | 'presentation.state.loading' | 'presentation.error.title' | 'presentation.error.parseFailed' | 'archive.error.nestedUnsupported' | 'archive.loading.readingDirectory' | 'archive.loading.readingDirectoryHint' | 'archive.search.placeholder' | 'archive.sidebar.hide' | 'archive.sidebar.show' | 'archive.preview.title' | 'archive.preview.chooseFile' | 'archive.preview.downloadFile' | 'archive.error.title' | 'archive.stats.summary' | 'archive.warning.encrypted' | 'archive.password.title' | 'archive.password.description' | 'archive.password.placeholder' | 'archive.password.invalid' | 'archive.password.required' | 'archive.password.cancel' | 'archive.password.confirm' | 'archive.error.passwordRequired' | 'archive.error.encryptedRequiresWorker' | 'archive.empty.title' | 'archive.empty.message' | 'archive.loading.initializingCandidate' | 'archive.loading.initializingCandidateHint' | 'archive.error.candidateInitTimeout' | 'archive.error.encryptedCheckTimeout' | 'archive.loading.directoryReadyHint' | 'archive.error.candidateReadTimeout' | 'archive.loading.workerFallback' | 'archive.loading.workerFallbackHint' | 'archive.notice.workerFallback' | 'archive.error.tooLarge' | 'archive.loading.initializingWorker' | 'archive.loading.initializingWorkerHint' | 'archive.error.workerInitFailed' | 'archive.error.workerUnsupported' | 'archive.error.indexedDbUnavailable' | 'archive.error.entryTooLarge' | 'archive.loading.extracting' | 'archive.loading.rendering' | 'archive.loading.exporting' | 'media.audio.title' | 'media.audio.description' | 'media.audio.unsupported' | 'media.video.title' | 'media.video.unsupported' | 'media.video.hlsHint' | 'media.midi.title' | 'media.midi.loading' | 'media.midi.trackHeader' | 'media.midi.instrumentHeader' | 'media.midi.channelHeader' | 'media.midi.noteCountHeader' | 'media.midi.durationHeader' | 'media.midi.durationStat' | 'media.midi.trackStat' | 'media.midi.noteStat' | 'media.midi.parseFailed' | 'email.mbox.subject' | 'email.mbox.summary' | 'email.error.title' | 'email.meta.from' | 'email.meta.to' | 'email.meta.cc' | 'email.meta.date' | 'email.tabs.text' | 'email.tabs.headers' | 'email.attachments.title' | 'email.attachments.empty' | 'email.attachments.download' | 'email.attachments.opening' | 'email.attachments.nestedUnavailable' | 'email.loading.parsing' | 'data.font.sample' | 'data.error.fontFaceUnsupported' | 'data.title.font' | 'data.title.sqlite' | 'data.title.parquet' | 'data.title.avro' | 'data.title.wasm' | 'data.title.eps' | 'data.title.ai' | 'data.title.webarchive' | 'data.title.summary' | 'data.label.format' | 'data.label.size' | 'data.label.rendering' | 'data.label.objects' | 'data.label.sampleTable' | 'data.label.rows' | 'data.label.columns' | 'data.label.sampleRows' | 'data.label.imports' | 'data.label.exports' | 'data.label.magic' | 'data.label.note' | 'data.label.container' | 'data.value.schemaRead' | 'data.value.schemaUnread' | 'data.note.aiSummary' | 'data.note.postscriptSummary' | 'data.note.webarchive' | 'data.image.alt' | 'psd.title' | 'psd.action.fit' | 'psd.action.showAll' | 'psd.action.hideAll' | 'psd.layers.title' | 'psd.layers.redrawable' | 'psd.layers.empty' | 'psd.layers.hidden' | 'drawing.error.viewerLoadFailed' | 'drawing.error.excalidrawEmpty' | 'drawing.error.excalidrawTimeout' | 'drawing.error.drawioParseFailed' | 'drawing.error.drawioNoModel' | 'drawing.error.drawioNoElements' | 'drawing.error.viewerInitFailed' | 'drawing.error.drawioTimeout' | 'drawing.error.svgParseFailed' | 'drawing.error.plantumlRenderFailed' | 'drawing.title.excalidraw' | 'drawing.title.mermaid' | 'drawing.title.plantuml' | 'drawing.title.drawio' | 'drawing.toolbar.zoomOut' | 'drawing.toolbar.zoomIn' | 'drawing.toolbar.fit' | 'drawing.toolbar.fitWidth' | 'drawing.state.loading' | 'text.code.loadingHighlight' | 'ebook.toc' | 'ebook.reading' | 'ebook.itemCount' | 'epub.title' | 'epub.previousPage' | 'epub.nextPage' | 'epub.loading' | 'epub.chapterFallback' | 'epub.renderIncomplete' | 'umd.title' | 'umd.previousChapter' | 'umd.nextChapter' | 'umd.loading' | 'umd.emptyContent' | 'umd.chapterFallback' | 'umd.galleryFallback' | 'umd.warningBodyTooShort' | 'umd.error.unexpectedEnd' | 'umd.error.invalidFile' | 'typst.summaryRenderer' | 'typst.pageSummary.empty' | 'typst.pageSummary.ready' | 'typst.status.compiling' | 'typst.status.failed' | 'typst.status.rendered' | 'typst.loading.title' | 'typst.loading.hint' | 'typst.error.title' | 'typst.error.timeout' | 'typst.error.timeoutHint' | 'typst.error.assetHint' | 'typst.error.svgParseFailed' | 'typst.error.wasmLoadFailed' | 'xmind.toolbar.zoomOut' | 'xmind.toolbar.zoomIn' | 'xmind.toolbar.fit' | 'xmind.toolbar.fitTitle' | 'xmind.state.loading' | 'xmind.stats.nodes' | 'xmind.stats.depth' | 'xmind.stats.theme' | 'xmind.stats.template' | 'xmind.badge.paused' | 'xmind.badge.collapsed' | 'xmind.badge.floating' | 'xmind.badge.summary' | 'xmind.badge.callout' | 'xmind.imageResource' | 'xmind.error.unrecognized' | 'xmind.error.noCanvas' | 'cad.toolbar.fit' | 'cad.toolbar.zoomOut' | 'cad.toolbar.zoomIn' | 'cad.layers.title' | 'cad.layers.count' | 'cad.inspector.title' | 'cad.inspector.entities' | 'cad.inspector.blocks' | 'cad.inspector.pages' | 'cad.inspector.drawn' | 'cad.state.loadingViewer' | 'cad.state.parsing' | 'cad.error.parseFailed' | 'image.alt' | 'image.lightbox.alt' | 'image.lightbox.close' | 'gitBundle.error.invalid' | 'gitBundle.error.missingPack' | 'gitBundle.notice.delta' | 'gitBundle.title.history' | 'gitBundle.title.fileTree' | 'gitBundle.file.choose' | 'gitBundle.file.noTree' | 'gitBundle.file.none' | 'gitBundle.history.empty' | 'gitBundle.toolbar.summary' | 'gitBundle.meta.bundle' | 'gitBundle.meta.refs' | 'gitBundle.meta.commits' | 'gitBundle.meta.objects' | 'gitBundle.meta.deltas' | 'gitBundle.meta.objectFormat' | 'gitBundle.meta.objectTypes' | 'geo.error.unrecognized' | 'geo.error.xmlParseFailed' | 'geo.error.unsupported' | 'geo.title' | 'geo.featureCount' | 'geo.bounds' | 'geo.geometryTypes' | 'geo.aria' | 'geo.loading' | 'geo.projection' | 'geo.engine' | 'geo.basemap' | 'geo.basemap.offline' | 'geo.basemap.custom' | 'geo.engine.maplibre' | 'geo.engine.svg' | 'geo.error.projection' | 'geo.action.fit' | 'model.toolbar.fit' | 'model.toolbar.rotate' | 'model.toolbar.wireframe' | 'model.toolbar.grid' | 'model.toolbar.axes' | 'model.state.loadingSummary' | 'model.state.loading' | 'model.state.loaded' | 'model.state.parseFailed' | 'model.summary.meshes' | 'model.summary.points' | 'model.error.daeEmpty' | 'model.error.unsupported' | 'model.error.parseFailed' | 'model.notice.signature' | 'loading.generic.label' | 'loading.generic.hint' | 'loading.word.label' | 'loading.word.hint' | 'loading.wordWorker.hint' | 'loading.sheet.label' | 'loading.sheet.hint' | 'loading.csv.label' | 'loading.csv.hint' | 'loading.presentation.label' | 'loading.presentation.hint' | 'loading.pdf.label' | 'loading.pdf.hint' | 'loading.ofd.label' | 'loading.ofd.hint' | 'loading.archive.label' | 'loading.archive.hint' | 'loading.email.label' | 'loading.email.hint' | 'loading.msg.hint' | 'loading.eda.label' | 'loading.eda.hint' | 'loading.cad.label' | 'loading.cad.hint' | 'loading.dwg.hint' | 'loading.dwf.hint' | 'loading.dwfx.hint' | 'loading.xps.hint' | 'loading.drawio.label' | 'loading.drawio.hint' | 'loading.excalidraw.label' | 'loading.excalidraw.hint' | 'loading.epub.label' | 'loading.epub.hint' | 'loading.umd.label' | 'loading.umd.hint' | 'loading.image.label' | 'loading.image.hint' | 'loading.video.label' | 'loading.video.hint' | 'loading.audio.label' | 'loading.audio.hint';
6
6
  export type FileViewerMessageParams = Record<string, string | number | boolean | null | undefined>;
7
7
  export type FileViewerMessageResolver = (key: FileViewerMessageKey, params: FileViewerMessageParams, locale: FileViewerLocale) => string | undefined;
8
8
  export type FileViewerMessages = Partial<Record<FileViewerMessageKey, string>> | FileViewerMessageResolver;
@@ -142,6 +142,8 @@ export interface FileViewerDocxOptions {
142
142
  updatePageReferences?: boolean;
143
143
  hideWebHiddenContent?: boolean;
144
144
  ignoreLastRenderedPageBreak?: boolean;
145
+ /** Overrides automatic DOCX dark rendering derived from the viewer theme. */
146
+ darkMode?: boolean;
145
147
  }
146
148
  export interface FileViewerSpreadsheetOptions {
147
149
  worker?: boolean | 'auto';
@@ -705,7 +707,8 @@ export interface FileViewerComponentEmits {
705
707
  export interface FileViewerPublicApi {
706
708
  destroy(): void;
707
709
  downloadOriginalFile(): Promise<void>;
708
- printRenderedHtml(): Promise<void>;
710
+ printRenderedHtml(options?: FileViewerPrintOptions): Promise<void>;
711
+ printWithMask(options?: FileViewerPrintOptions): Promise<void>;
709
712
  exportRenderedHtml(): Promise<void>;
710
713
  zoomIn(): Promise<FileViewerZoomState>;
711
714
  zoomOut(): Promise<FileViewerZoomState>;
@@ -735,12 +738,27 @@ export interface FileViewerExportHtmlOptions {
735
738
  title?: string;
736
739
  watermarkInlineStyle?: string;
737
740
  }
741
+ /** Normalized print-mask rectangle in percent of the rendered content box. */
742
+ export interface FileViewerPrintMaskRegion {
743
+ left: number;
744
+ top: number;
745
+ width: number;
746
+ height: number;
747
+ }
748
+ export interface FileViewerPrintMaskOptions {
749
+ /** Solid black cover blocks, matching common OFD/business redaction UX. */
750
+ regions?: FileViewerPrintMaskRegion[];
751
+ /** Fill color for print masks. Defaults to opaque black. */
752
+ color?: string;
753
+ }
738
754
  export interface FileViewerPrintOptions {
739
755
  autoPrint?: boolean;
740
756
  openWindow?: () => Window | null;
741
757
  printWindow?: Window | null;
742
758
  title?: string;
743
759
  watermarkInlineStyle?: string;
760
+ /** Optional print-time cover masks applied above content and below watermark. */
761
+ mask?: FileViewerPrintMaskOptions | null;
744
762
  }
745
763
  export interface FileViewerSource {
746
764
  url?: string;
@@ -855,6 +873,8 @@ export interface FileViewerInstance {
855
873
  download(options?: FileViewerDownloadOptions): Promise<void>;
856
874
  exportHtml(options?: FileViewerExportHtmlOptions): Promise<string>;
857
875
  print(options?: FileViewerPrintOptions): Promise<void>;
876
+ /** Open the async print-mask designer, then print with the chosen covers. */
877
+ printWithMask(options?: FileViewerPrintOptions): Promise<void>;
858
878
  zoomIn(): Promise<FileViewerZoomState>;
859
879
  zoomOut(): Promise<FileViewerZoomState>;
860
880
  resetZoom(): Promise<FileViewerZoomState>;
@@ -0,0 +1,5 @@
1
+ import type { FileViewerPrintMaskOptions, FileViewerPrintMaskRegion } from '../contracts/types';
2
+ export declare const normalizeFileViewerPrintMaskRegion: (region: Partial<FileViewerPrintMaskRegion> | null | undefined) => FileViewerPrintMaskRegion | null;
3
+ export declare const normalizeFileViewerPrintMaskOptions: (mask?: FileViewerPrintMaskOptions | null) => FileViewerPrintMaskOptions | null;
4
+ export declare const buildFileViewerPrintMaskOverlayHtml: (mask?: FileViewerPrintMaskOptions | null) => string;
5
+ export declare const FILE_VIEWER_PRINT_MASK_STYLE = "\n .viewer-export-print-mask{position:absolute;inset:0;z-index:15;pointer-events:none;print-color-adjust:exact;-webkit-print-color-adjust:exact;}\n .viewer-export-print-mask-block{position:absolute;box-sizing:border-box;print-color-adjust:exact;-webkit-print-color-adjust:exact;}\n";
@@ -0,0 +1,48 @@
1
+ const clampPercent = (value) => Math.max(0, Math.min(100, value));
2
+ export const normalizeFileViewerPrintMaskRegion = (region) => {
3
+ if (!region) {
4
+ return null;
5
+ }
6
+ const left = clampPercent(Number(region.left) || 0);
7
+ const top = clampPercent(Number(region.top) || 0);
8
+ const width = clampPercent(Number(region.width) || 0);
9
+ const height = clampPercent(Number(region.height) || 0);
10
+ if (width <= 0 || height <= 0) {
11
+ return null;
12
+ }
13
+ return {
14
+ left,
15
+ top,
16
+ width: Math.min(width, 100 - left),
17
+ height: Math.min(height, 100 - top),
18
+ };
19
+ };
20
+ export const normalizeFileViewerPrintMaskOptions = (mask) => {
21
+ if (!mask || !Array.isArray(mask.regions) || !mask.regions.length) {
22
+ return null;
23
+ }
24
+ const regions = mask.regions
25
+ .map(region => normalizeFileViewerPrintMaskRegion(region))
26
+ .filter((region) => !!region);
27
+ if (!regions.length) {
28
+ return null;
29
+ }
30
+ return {
31
+ regions,
32
+ color: mask.color || '#000000',
33
+ };
34
+ };
35
+ export const buildFileViewerPrintMaskOverlayHtml = (mask) => {
36
+ var _a;
37
+ const normalized = normalizeFileViewerPrintMaskOptions(mask);
38
+ if (!((_a = normalized === null || normalized === void 0 ? void 0 : normalized.regions) === null || _a === void 0 ? void 0 : _a.length)) {
39
+ return '';
40
+ }
41
+ const color = normalized.color || '#000000';
42
+ const blocks = normalized.regions.map(region => (`<div class="viewer-export-print-mask-block" style="left:${region.left}%;top:${region.top}%;width:${region.width}%;height:${region.height}%;background:${color};"></div>`)).join('');
43
+ return `<div class="viewer-export-print-mask" aria-hidden="true">${blocks}</div>`;
44
+ };
45
+ export const FILE_VIEWER_PRINT_MASK_STYLE = `
46
+ .viewer-export-print-mask{position:absolute;inset:0;z-index:15;pointer-events:none;print-color-adjust:exact;-webkit-print-color-adjust:exact;}
47
+ .viewer-export-print-mask-block{position:absolute;box-sizing:border-box;print-color-adjust:exact;-webkit-print-color-adjust:exact;}
48
+ `;
@@ -0,0 +1,16 @@
1
+ import type { FileViewerPrintMaskOptions, FileViewerPrintMaskRegion } from '../contracts/types';
2
+ import { type FileViewerI18nInput } from '../i18n/messages';
3
+ export interface OpenFileViewerPrintMaskDesignerOptions {
4
+ root: HTMLElement;
5
+ i18n?: FileViewerI18nInput;
6
+ color?: string;
7
+ initialRegions?: FileViewerPrintMaskRegion[];
8
+ }
9
+ export interface FileViewerPrintMaskDesignerResult {
10
+ mask: FileViewerPrintMaskOptions;
11
+ }
12
+ /**
13
+ * Opens an interactive print-mask designer over the rendered content.
14
+ * Loaded asynchronously so the main viewer bundle stays lean.
15
+ */
16
+ export declare const openFileViewerPrintMaskDesigner: (options: OpenFileViewerPrintMaskDesignerOptions) => Promise<FileViewerPrintMaskDesignerResult | null>;
@@ -0,0 +1,200 @@
1
+ import { createFileViewerTranslator } from '../i18n/messages.js';
2
+ import { normalizeFileViewerPrintMaskRegion } from './printMask.js';
3
+ const DESIGNER_STYLE = `
4
+ .fv-print-mask-layer{position:absolute;inset:0;z-index:40;pointer-events:none;}
5
+ .fv-print-mask-canvas{position:absolute;inset:0;pointer-events:auto;cursor:crosshair;touch-action:none;}
6
+ .fv-print-mask-block{position:absolute;background:#000;box-sizing:border-box;pointer-events:auto;}
7
+ .fv-print-mask-block-remove{position:absolute;right:-8px;top:-8px;width:18px;height:18px;border:0;border-radius:999px;background:#111;color:#fff;font:700 12px/18px system-ui,sans-serif;cursor:pointer;padding:0;}
8
+ .fv-print-mask-toolbar{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);z-index:41;display:inline-flex;align-items:center;gap:6px;padding:6px 8px;border:1px solid rgba(20,35,53,.12);border-radius:999px;background:rgba(255,255,255,.94);box-shadow:0 12px 28px rgba(15,23,42,.16);pointer-events:auto;max-width:calc(100% - 24px);flex-wrap:wrap;justify-content:center;}
9
+ .fv-print-mask-toolbar span{font:600 12px/1.2 system-ui,sans-serif;color:#40546a;white-space:nowrap;}
10
+ .fv-print-mask-toolbar button{min-width:42px;height:30px;padding:0 10px;border:0;border-radius:999px;background:transparent;color:#40546a;font:800 12px/1 system-ui,sans-serif;cursor:pointer;}
11
+ .fv-print-mask-toolbar button:hover{background:rgba(33,163,102,.1);color:#16774c;}
12
+ .fv-print-mask-toolbar button.primary{background:#16774c;color:#fff;}
13
+ .fv-print-mask-toolbar button.primary:hover{background:#0f5f3c;}
14
+ `;
15
+ const ensureDesignerStyle = (documentRef) => {
16
+ if (documentRef.getElementById('fv-print-mask-designer-style')) {
17
+ return;
18
+ }
19
+ const style = documentRef.createElement('style');
20
+ style.id = 'fv-print-mask-designer-style';
21
+ style.textContent = DESIGNER_STYLE;
22
+ documentRef.head.appendChild(style);
23
+ };
24
+ const toPercentRegion = (start, end, bounds) => {
25
+ if (!bounds.width || !bounds.height) {
26
+ return null;
27
+ }
28
+ const leftPx = Math.min(start.x, end.x);
29
+ const topPx = Math.min(start.y, end.y);
30
+ const widthPx = Math.abs(end.x - start.x);
31
+ const heightPx = Math.abs(end.y - start.y);
32
+ if (widthPx < 8 || heightPx < 8) {
33
+ return null;
34
+ }
35
+ return normalizeFileViewerPrintMaskRegion({
36
+ left: (leftPx / bounds.width) * 100,
37
+ top: (topPx / bounds.height) * 100,
38
+ width: (widthPx / bounds.width) * 100,
39
+ height: (heightPx / bounds.height) * 100,
40
+ });
41
+ };
42
+ /**
43
+ * Opens an interactive print-mask designer over the rendered content.
44
+ * Loaded asynchronously so the main viewer bundle stays lean.
45
+ */
46
+ export const openFileViewerPrintMaskDesigner = (options) => {
47
+ const root = options.root;
48
+ const documentRef = root.ownerDocument;
49
+ const t = createFileViewerTranslator(options.i18n);
50
+ const color = options.color || '#000000';
51
+ const regions = [...(options.initialRegions || [])]
52
+ .map(region => normalizeFileViewerPrintMaskRegion(region))
53
+ .filter((region) => !!region);
54
+ ensureDesignerStyle(documentRef);
55
+ const previousPosition = root.style.position;
56
+ if (!previousPosition || previousPosition === 'static') {
57
+ root.style.position = 'relative';
58
+ }
59
+ return new Promise(resolve => {
60
+ let settled = false;
61
+ let drawing = null;
62
+ const layer = documentRef.createElement('div');
63
+ layer.className = 'fv-print-mask-layer';
64
+ layer.setAttribute('data-viewer-print-mask-designer', 'true');
65
+ const canvas = documentRef.createElement('div');
66
+ canvas.className = 'fv-print-mask-canvas';
67
+ const toolbar = documentRef.createElement('div');
68
+ toolbar.className = 'fv-print-mask-toolbar';
69
+ toolbar.setAttribute('role', 'toolbar');
70
+ toolbar.setAttribute('aria-label', t('toolbar.printMaskTitle'));
71
+ const hint = documentRef.createElement('span');
72
+ hint.textContent = t('toolbar.printMaskHint');
73
+ const clearButton = documentRef.createElement('button');
74
+ clearButton.type = 'button';
75
+ clearButton.textContent = t('toolbar.printMaskClear');
76
+ const cancelButton = documentRef.createElement('button');
77
+ cancelButton.type = 'button';
78
+ cancelButton.textContent = t('toolbar.printMaskCancel');
79
+ const confirmButton = documentRef.createElement('button');
80
+ confirmButton.type = 'button';
81
+ confirmButton.className = 'primary';
82
+ confirmButton.textContent = t('toolbar.printMaskConfirm');
83
+ toolbar.append(hint, clearButton, cancelButton, confirmButton);
84
+ layer.append(canvas, toolbar);
85
+ root.appendChild(layer);
86
+ const finish = (result) => {
87
+ if (settled) {
88
+ return;
89
+ }
90
+ settled = true;
91
+ layer.remove();
92
+ if (!previousPosition) {
93
+ root.style.removeProperty('position');
94
+ }
95
+ else {
96
+ root.style.position = previousPosition;
97
+ }
98
+ resolve(result);
99
+ };
100
+ const renderRegions = () => {
101
+ canvas.replaceChildren();
102
+ regions.forEach((region, index) => {
103
+ const block = documentRef.createElement('div');
104
+ block.className = 'fv-print-mask-block';
105
+ block.style.left = `${region.left}%`;
106
+ block.style.top = `${region.top}%`;
107
+ block.style.width = `${region.width}%`;
108
+ block.style.height = `${region.height}%`;
109
+ block.style.background = color;
110
+ const remove = documentRef.createElement('button');
111
+ remove.type = 'button';
112
+ remove.className = 'fv-print-mask-block-remove';
113
+ remove.title = t('toolbar.printMaskClear');
114
+ remove.setAttribute('aria-label', t('toolbar.printMaskClear'));
115
+ remove.textContent = '−';
116
+ remove.addEventListener('click', event => {
117
+ event.preventDefault();
118
+ event.stopPropagation();
119
+ regions.splice(index, 1);
120
+ renderRegions();
121
+ });
122
+ block.appendChild(remove);
123
+ canvas.appendChild(block);
124
+ });
125
+ };
126
+ const pointFromEvent = (event) => {
127
+ const bounds = canvas.getBoundingClientRect();
128
+ return {
129
+ x: Math.max(0, Math.min(bounds.width, event.clientX - bounds.left)),
130
+ y: Math.max(0, Math.min(bounds.height, event.clientY - bounds.top)),
131
+ };
132
+ };
133
+ canvas.addEventListener('pointerdown', event => {
134
+ if (event.button !== 0) {
135
+ return;
136
+ }
137
+ event.preventDefault();
138
+ const start = pointFromEvent(event);
139
+ const preview = documentRef.createElement('div');
140
+ preview.className = 'fv-print-mask-block';
141
+ preview.style.background = color;
142
+ preview.style.opacity = '0.72';
143
+ canvas.appendChild(preview);
144
+ drawing = { start, preview };
145
+ canvas.setPointerCapture(event.pointerId);
146
+ });
147
+ canvas.addEventListener('pointermove', event => {
148
+ if (!drawing) {
149
+ return;
150
+ }
151
+ const end = pointFromEvent(event);
152
+ const left = Math.min(drawing.start.x, end.x);
153
+ const top = Math.min(drawing.start.y, end.y);
154
+ drawing.preview.style.left = `${left}px`;
155
+ drawing.preview.style.top = `${top}px`;
156
+ drawing.preview.style.width = `${Math.abs(end.x - drawing.start.x)}px`;
157
+ drawing.preview.style.height = `${Math.abs(end.y - drawing.start.y)}px`;
158
+ });
159
+ const endDrawing = (event) => {
160
+ if (!drawing) {
161
+ return;
162
+ }
163
+ const end = pointFromEvent(event);
164
+ const bounds = canvas.getBoundingClientRect();
165
+ const region = toPercentRegion(drawing.start, end, bounds);
166
+ drawing.preview.remove();
167
+ drawing = null;
168
+ try {
169
+ canvas.releasePointerCapture(event.pointerId);
170
+ }
171
+ catch {
172
+ // ignore
173
+ }
174
+ if (region) {
175
+ regions.push(region);
176
+ renderRegions();
177
+ }
178
+ };
179
+ canvas.addEventListener('pointerup', endDrawing);
180
+ canvas.addEventListener('pointercancel', endDrawing);
181
+ clearButton.addEventListener('click', () => {
182
+ regions.splice(0, regions.length);
183
+ renderRegions();
184
+ });
185
+ cancelButton.addEventListener('click', () => finish(null));
186
+ confirmButton.addEventListener('click', () => {
187
+ if (!regions.length) {
188
+ finish(null);
189
+ return;
190
+ }
191
+ finish({
192
+ mask: {
193
+ regions: regions.map(region => ({ ...region })),
194
+ color,
195
+ },
196
+ });
197
+ });
198
+ renderRegions();
199
+ });
200
+ };
@@ -0,0 +1,8 @@
1
+ import type { FileViewerPrintMaskDesignerResult, OpenFileViewerPrintMaskDesignerOptions } from './printMaskDesigner';
2
+ /**
3
+ * Lazily opens the print-mask designer.
4
+ * Kept as a dynamic import so the designer stays out of the main core graph,
5
+ * while remaining reachable through the primary `@file-viewer/core` entry
6
+ * (no consumer alias / subpath setup required).
7
+ */
8
+ export declare const openFileViewerPrintMaskDesignerAsync: (options: OpenFileViewerPrintMaskDesignerOptions) => Promise<FileViewerPrintMaskDesignerResult | null>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Lazily opens the print-mask designer.
3
+ * Kept as a dynamic import so the designer stays out of the main core graph,
4
+ * while remaining reachable through the primary `@file-viewer/core` entry
5
+ * (no consumer alias / subpath setup required).
6
+ */
7
+ export const openFileViewerPrintMaskDesignerAsync = async (options) => {
8
+ const { openFileViewerPrintMaskDesigner } = await import('../print-mask.js');
9
+ return openFileViewerPrintMaskDesigner(options);
10
+ };
@@ -9,6 +9,14 @@ const ZH_CN_MESSAGES = {
9
9
  'toolbar.downloadTitle': '下载原始文件',
10
10
  'toolbar.print': '打印',
11
11
  'toolbar.printTitle': '打印完整渲染内容',
12
+ 'toolbar.printDirect': '直接打印',
13
+ 'toolbar.printMask': '掩膜打印',
14
+ 'toolbar.printMaskTitle': '遮盖敏感区域后再打印',
15
+ 'toolbar.printMaskAdd': '添加掩膜',
16
+ 'toolbar.printMaskClear': '清空',
17
+ 'toolbar.printMaskCancel': '取消',
18
+ 'toolbar.printMaskConfirm': '确认打印',
19
+ 'toolbar.printMaskHint': '拖拽绘制黑色遮盖块,可删除后继续调整',
12
20
  'toolbar.exportHtml': 'HTML',
13
21
  'toolbar.exportHtmlTitle': '导出当前渲染后的 HTML',
14
22
  'toolbar.search': '搜索',
@@ -411,6 +419,14 @@ const EN_US_MESSAGES = {
411
419
  'toolbar.downloadTitle': 'Download the original file',
412
420
  'toolbar.print': 'Print',
413
421
  'toolbar.printTitle': 'Print the complete rendered document',
422
+ 'toolbar.printDirect': 'Print now',
423
+ 'toolbar.printMask': 'Mask & print',
424
+ 'toolbar.printMaskTitle': 'Cover sensitive areas before printing',
425
+ 'toolbar.printMaskAdd': 'Add mask',
426
+ 'toolbar.printMaskClear': 'Clear',
427
+ 'toolbar.printMaskCancel': 'Cancel',
428
+ 'toolbar.printMaskConfirm': 'Print',
429
+ 'toolbar.printMaskHint': 'Drag to draw black cover blocks. Delete and adjust as needed.',
414
430
  'toolbar.exportHtml': 'HTML',
415
431
  'toolbar.exportHtmlTitle': 'Export the rendered HTML',
416
432
  'toolbar.search': 'Search',
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export type { ApplyInitialFileViewerFitOptions, CreateFileViewerFitControllerOpt
13
13
  export { cloneFileViewerViewState, createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerViewStateController, createFileViewerViewStateControllerActionHandlers, registerFileViewerGenericViewStateProvider, } from './features/document/viewState';
14
14
  export type { CreateFileViewerViewStateControllerOptions, FileViewerGenericViewStateProviderRegistration, FileViewerViewStateController, FileViewerViewStateControllerActionHandlers, RegisterFileViewerGenericViewStateProviderOptions, } from './features/document/viewState';
15
15
  export { DEFAULT_FILE_VIEWER_ANCHOR_EXCLUDE_SELECTOR, DEFAULT_FILE_VIEWER_ANCHOR_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_CANDIDATE_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_SELECTOR, DEFAULT_FILE_VIEWER_SCROLLABLE_OVERFLOW_VALUES, collectFileViewerDocumentAnchors, findFileViewerAnchorForElement, findFileViewerSearchProvider, findFileViewerViewStateProvider, findFileViewerZoomProvider, getCurrentFileViewerDocumentAnchor, getFileViewerScrollableRange, isFileViewerScrollableElement, registerFileViewerSearchProvider, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerScrollContainer, scrollToFileViewerDocumentAnchor, unregisterFileViewerSearchProvider, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from './features/document/dom';
16
- export { buildFileViewerRenderedHtmlDocument, buildExportHtmlDocument, collectDocumentStyles, prepareFileViewerRenderedContentForSnapshot, replaceFileViewerCanvasWithImages, resolveFileViewerPrintStyle, triggerFileViewerBlobDownload, triggerFileViewerUrlDownload, waitForFileViewerImages, waitForFileViewerNextPaint, waitForFileViewerPrintWindowReady, } from './output/export';
16
+ export { buildFileViewerRenderedHtmlDocument, buildExportHtmlDocument, collectDocumentStyles, prepareFileViewerRenderedContentForSnapshot, inlineFileViewerBlobUrlsInHtml, replaceFileViewerCanvasWithImages, resolveFileViewerPrintStyle, triggerFileViewerBlobDownload, triggerFileViewerUrlDownload, waitForFileViewerImages, waitForFileViewerNextPaint, waitForFileViewerPrintWindowReady, } from './output/export';
17
17
  export { applyPrintPageSize, buildPrintPageStyle, formatCssPixels, getElementPrintPageSize, } from './output/printLayout';
18
18
  export type { ApplyPrintPageSizeOptions, BuildPrintPageStyleOptions, PrintPageSize, } from './output/printLayout';
19
19
  export { DEFAULT_FILE_VIEWER_DOWNLOAD_FILENAME, DEFAULT_FILE_VIEWER_EXPORT_FILENAME, DEFAULT_FILE_VIEWER_PREVIEW_TITLE, FILE_VIEWER_OPERATION_ACTION_ERROR_PREFIXES, createFileViewerOperationActionHandlers, createFileViewerOriginalSourceState, createFileViewerOriginalSourceStateFromNormalizedSource, createFileViewerPublicOperationActionHandlers, executeFileViewerDownloadOperation, executeFileViewerExportHtmlOperation, executeFileViewerPrintOperation, hasFileViewerOriginalSource, resolveFileViewerDisplayFilename, resolveFileViewerOperationActionErrorMessage, resolveFileViewerOperationFilename, resolveFileViewerOriginalFilename, } from './viewer/operations';
@@ -67,6 +67,9 @@ export { DEFAULT_FILE_VIEWER_STATE_THEME, DEFAULT_FILE_VIEWER_UNSUPPORTED_DESCRI
67
67
  export type { FileViewerErrorMessageFormatter, FileViewerRendererInstallHint, } from './viewer/state';
68
68
  export { buildFileViewerWatermarkBackgroundImage, buildFileViewerWatermarkInlineStyle, buildFileViewerWatermarkStyle, buildFileViewerWatermarkSvg, normalizeFileViewerWatermark, resolveFileViewerWatermarkPresentationState, } from './features/watermark';
69
69
  export type { FileViewerWatermarkPresentationState, FileViewerWatermarkStyle, } from './features/watermark';
70
+ export { buildFileViewerPrintMaskOverlayHtml, normalizeFileViewerPrintMaskOptions, normalizeFileViewerPrintMaskRegion, FILE_VIEWER_PRINT_MASK_STYLE, } from './features/printMask';
71
+ export { openFileViewerPrintMaskDesignerAsync, } from './features/printMaskLoader';
72
+ export type { FileViewerPrintMaskDesignerResult, OpenFileViewerPrintMaskDesignerOptions, } from './features/printMaskDesigner';
70
73
  export { cancelFileViewerPreviewRequest, DEFAULT_FILE_VIEWER_STREAMING_PDF_FILENAME, DEFAULT_FILE_VIEWER_PREVIEW_LOAD_ERROR_LOGGER, DEFAULT_PDF_RANGE_CHUNK_SIZE, FILE_VIEWER_PREVIEW_LOAD_ERROR_PREFIXES, FILE_VIEWER_REMOTE_MISSING_DATA_ERROR_MESSAGE, applyFileViewerEmptyPreviewState, applyFileViewerPreviewFilenameState, applyFileViewerPreviewSourceUrlState, applyFileViewerReadPreviewState, applyFileViewerRenderReadinessState, applyFileViewerPreviewRequestResetState, commitFileViewerEmptyPreviewResetState, commitFileViewerLoadStartState, commitFileViewerPreviewRequestStartState, commitFileViewerRenderCompleteState, commitFileViewerRemoteDownloadState, createFileViewerEmptyPreviewState, createFileViewerLoadStartState, createFileViewerPreviewStateTarget, createFileViewerSourceLoadingActionHandlers, createFileViewerReadPreviewState, createFileViewerPreviewRequestResetState, createFileViewerRenderCompleteState, createFileViewerRequestController, createFileViewerRequestScope, createFileViewerStreamingPdfPlaceholderFile, finalizeFileViewerPreviewLoadState, hasFileViewerPreviewSource, isFileViewerAbortError, isSameOriginUrl, normalizeFileViewerSourceUrl, normalizePdfStreamingMode, resolveFileViewerFileRefSourcePlan, resolveFileViewerLoadStartMessage, resolveFileViewerMissingRemoteDataErrorMessage, resolveFileViewerPreviewLoadErrorMessage, resolveFileViewerPreviewRequestReason, resolveFileViewerRemoteSourcePlan, resolveFileViewerPageHref, reportFileViewerMissingRemoteData, reportFileViewerPreviewLoadError, runFileViewerLocalFilePreview, runFileViewerPreviewComponentUnmount, runFileViewerPreviewRequest, runFileViewerPreviewSourceChange, runFileViewerRemoteFilePreview, runFileViewerReadAndRenderFile, runFileViewerStreamingPdfPreview, shouldStreamPdfUrl, } from './source/loading';
71
74
  export type { CreateFileViewerPreviewStateTargetInput, CreateFileViewerSourceLoadingActionHandlersInput, CreateFileViewerLoadStartStateInput, CreateFileViewerReadPreviewStateInput, CreateFileViewerRenderCompleteStateInput, CommitFileViewerEmptyPreviewResetStateInput, CancelFileViewerPreviewRequestInput, CommitFileViewerLoadStartStateInput, CommitFileViewerPreviewRequestStartStateInput, CommitFileViewerRenderCompleteStateInput, CommitFileViewerRemoteDownloadStateInput, FileViewerEmptyPreviewState, FileViewerMutableAccessor, FileViewerLocationLike, FileViewerFileRefSourcePlan, FileViewerLocalFilePreviewState, FileViewerLoadStartState, FileViewerPreviewLoadErrorKind, FileViewerPreviewLoadErrorPrefixes, FileViewerPreviewLoadErrorLogger, FileViewerPreviewComponentUnmountState, FileViewerPreviewRequestResetState, FileViewerSourceLoadingActionHandlers, FileViewerReadAndRenderFileState, FileViewerRenderCompleteState, FileViewerRenderReadinessState, FileViewerRemoteDownloadState, FileViewerRemoteFilePreviewErrorKind, FileViewerRemoteFilePreviewState, FileViewerRemoteFileDownloadInput, FileViewerReadPreviewState, FileViewerPreviewRequestRunState, FileViewerRemoteSourcePlan, FileViewerRequestController, FileViewerRequestScope, FileViewerStreamingPdfPreviewState, FinalizeFileViewerPreviewLoadStateInput, MutableFileViewerPreviewFilenameState, MutableFileViewerPreviewSourceUrlState, MutableFileViewerPreviewRequestState, MutableFileViewerPreviewState, MutableFileViewerRenderReadinessState, MutableFileViewerReadPreviewState, RunFileViewerLocalFilePreviewInput, RunFileViewerPreviewComponentUnmountInput, RunFileViewerPreviewRequestInput, RunFileViewerPreviewSourceChangeInput, RunFileViewerRemoteFilePreviewInput, RunFileViewerReadAndRenderFileInput, RunFileViewerStreamingPdfPreviewInput, ResolveFileViewerFileRefSourcePlanInput, ResolveFileViewerMissingRemoteDataErrorMessageInput, ResolveFileViewerPreviewLoadErrorMessageInput, ResolveFileViewerPreviewRequestReasonInput, ReportFileViewerMissingRemoteDataInput, ReportFileViewerPreviewLoadErrorInput, } from './source/loading';
72
75
  export { createViewer } from './viewer/createViewer';
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ export { applyFileViewerZoomState, clearFileViewerZoomControllerProvider, create
7
7
  export { FILE_VIEWER_FIT_MODES, FILE_VIEWER_FIT_RESIZE_MODES, createFileViewerFitController, hasFileViewerExplicitInitialViewState, isFileViewerFitMode, isFileViewerFitResize, normalizeFileViewerFitOptions, resolveFileViewerFitScale, } from './features/document/fit.js';
8
8
  export { cloneFileViewerViewState, createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerViewStateController, createFileViewerViewStateControllerActionHandlers, registerFileViewerGenericViewStateProvider, } from './features/document/viewState.js';
9
9
  export { DEFAULT_FILE_VIEWER_ANCHOR_EXCLUDE_SELECTOR, DEFAULT_FILE_VIEWER_ANCHOR_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_CANDIDATE_SELECTOR, DEFAULT_FILE_VIEWER_SCROLL_CONTAINER_SELECTOR, DEFAULT_FILE_VIEWER_SCROLLABLE_OVERFLOW_VALUES, collectFileViewerDocumentAnchors, findFileViewerAnchorForElement, findFileViewerSearchProvider, findFileViewerViewStateProvider, findFileViewerZoomProvider, getCurrentFileViewerDocumentAnchor, getFileViewerScrollableRange, isFileViewerScrollableElement, registerFileViewerSearchProvider, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerScrollContainer, scrollToFileViewerDocumentAnchor, unregisterFileViewerSearchProvider, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from './features/document/dom/index.js';
10
- export { buildFileViewerRenderedHtmlDocument, buildExportHtmlDocument, collectDocumentStyles, prepareFileViewerRenderedContentForSnapshot, replaceFileViewerCanvasWithImages, resolveFileViewerPrintStyle, triggerFileViewerBlobDownload, triggerFileViewerUrlDownload, waitForFileViewerImages, waitForFileViewerNextPaint, waitForFileViewerPrintWindowReady, } from './output/export.js';
10
+ export { buildFileViewerRenderedHtmlDocument, buildExportHtmlDocument, collectDocumentStyles, prepareFileViewerRenderedContentForSnapshot, inlineFileViewerBlobUrlsInHtml, replaceFileViewerCanvasWithImages, resolveFileViewerPrintStyle, triggerFileViewerBlobDownload, triggerFileViewerUrlDownload, waitForFileViewerImages, waitForFileViewerNextPaint, waitForFileViewerPrintWindowReady, } from './output/export.js';
11
11
  export { applyPrintPageSize, buildPrintPageStyle, formatCssPixels, getElementPrintPageSize, } from './output/printLayout.js';
12
12
  export { DEFAULT_FILE_VIEWER_DOWNLOAD_FILENAME, DEFAULT_FILE_VIEWER_EXPORT_FILENAME, DEFAULT_FILE_VIEWER_PREVIEW_TITLE, FILE_VIEWER_OPERATION_ACTION_ERROR_PREFIXES, createFileViewerOperationActionHandlers, createFileViewerOriginalSourceState, createFileViewerOriginalSourceStateFromNormalizedSource, createFileViewerPublicOperationActionHandlers, executeFileViewerDownloadOperation, executeFileViewerExportHtmlOperation, executeFileViewerPrintOperation, hasFileViewerOriginalSource, resolveFileViewerDisplayFilename, resolveFileViewerOperationActionErrorMessage, resolveFileViewerOperationFilename, resolveFileViewerOriginalFilename, } from './viewer/operations.js';
13
13
  export { FILE_VIEWER_BUILTIN_MESSAGES, FILE_VIEWER_DEFAULT_LOCALE, FILE_VIEWER_FALLBACK_LOCALE, createFileViewerTranslator, formatFileViewerMessage, normalizeFileViewerLocale, resolveFileViewerLocale, translateFileViewerMessage, } from './i18n/messages.js';
@@ -173,6 +173,8 @@ export { appendFileViewerStyle, buildFileRenderContextFromLoadContext, applyFile
173
173
  export { DEFAULT_FILE_VIEWER_SOURCE_FILENAME, decodeFilename, getExtension, normalizeFileExtension, normalizeFilename, resolveFileViewerSourceFilename, normalizeSource, readFileViewerBuffer, readFileViewerDataUrl, readFileViewerText, wrapFileViewerFileRef, } from './source/index.js';
174
174
  export { DEFAULT_FILE_VIEWER_STATE_THEME, DEFAULT_FILE_VIEWER_UNSUPPORTED_DESCRIPTION, FILE_VIEWER_PREVIEW_MESSAGES, createFileViewerEmptyState, createFileViewerErrorState, createFileViewerPreviewLoadingState, createFileViewerReadyState, createFileViewerUnsupportedState, formatFileViewerErrorMessage, normalizeFileViewerErrorMessage, resolveFileViewerRendererInstallHint, } from './viewer/state.js';
175
175
  export { buildFileViewerWatermarkBackgroundImage, buildFileViewerWatermarkInlineStyle, buildFileViewerWatermarkStyle, buildFileViewerWatermarkSvg, normalizeFileViewerWatermark, resolveFileViewerWatermarkPresentationState, } from './features/watermark.js';
176
+ export { buildFileViewerPrintMaskOverlayHtml, normalizeFileViewerPrintMaskOptions, normalizeFileViewerPrintMaskRegion, FILE_VIEWER_PRINT_MASK_STYLE, } from './features/printMask.js';
177
+ export { openFileViewerPrintMaskDesignerAsync, } from './features/printMaskLoader.js';
176
178
  export { cancelFileViewerPreviewRequest, DEFAULT_FILE_VIEWER_STREAMING_PDF_FILENAME, DEFAULT_FILE_VIEWER_PREVIEW_LOAD_ERROR_LOGGER, DEFAULT_PDF_RANGE_CHUNK_SIZE, FILE_VIEWER_PREVIEW_LOAD_ERROR_PREFIXES, FILE_VIEWER_REMOTE_MISSING_DATA_ERROR_MESSAGE, applyFileViewerEmptyPreviewState, applyFileViewerPreviewFilenameState, applyFileViewerPreviewSourceUrlState, applyFileViewerReadPreviewState, applyFileViewerRenderReadinessState, applyFileViewerPreviewRequestResetState, commitFileViewerEmptyPreviewResetState, commitFileViewerLoadStartState, commitFileViewerPreviewRequestStartState, commitFileViewerRenderCompleteState, commitFileViewerRemoteDownloadState, createFileViewerEmptyPreviewState, createFileViewerLoadStartState, createFileViewerPreviewStateTarget, createFileViewerSourceLoadingActionHandlers, createFileViewerReadPreviewState, createFileViewerPreviewRequestResetState, createFileViewerRenderCompleteState, createFileViewerRequestController, createFileViewerRequestScope, createFileViewerStreamingPdfPlaceholderFile, finalizeFileViewerPreviewLoadState, hasFileViewerPreviewSource, isFileViewerAbortError, isSameOriginUrl, normalizeFileViewerSourceUrl, normalizePdfStreamingMode, resolveFileViewerFileRefSourcePlan, resolveFileViewerLoadStartMessage, resolveFileViewerMissingRemoteDataErrorMessage, resolveFileViewerPreviewLoadErrorMessage, resolveFileViewerPreviewRequestReason, resolveFileViewerRemoteSourcePlan, resolveFileViewerPageHref, reportFileViewerMissingRemoteData, reportFileViewerPreviewLoadError, runFileViewerLocalFilePreview, runFileViewerPreviewComponentUnmount, runFileViewerPreviewRequest, runFileViewerPreviewSourceChange, runFileViewerRemoteFilePreview, runFileViewerReadAndRenderFile, runFileViewerStreamingPdfPreview, shouldStreamPdfUrl, } from './source/loading.js';
177
179
  export { createViewer } from './viewer/createViewer.js';
178
180
  export { WorkerRefImpl, createFileViewerWorkerController, refWorker, } from './platform/worker.js';
@@ -1,26 +1,33 @@
1
- import type { FileRenderExportAdapter, FileRenderExportMode, FileRenderExportOptions } from '../contracts/types';
1
+ import type { FileRenderExportAdapter, FileRenderExportMode, FileRenderExportOptions, FileViewerPrintMaskOptions } from '../contracts/types';
2
2
  export interface BuildExportHtmlDocumentOptions {
3
3
  contentHtml: string;
4
4
  includeDocumentStyles?: boolean;
5
5
  printStyle?: string;
6
6
  title: string;
7
7
  watermarkInlineStyle?: string;
8
+ mask?: FileViewerPrintMaskOptions | null;
8
9
  }
9
10
  export declare const collectDocumentStyles: () => string;
10
- export declare const buildExportHtmlDocument: ({ contentHtml, includeDocumentStyles, printStyle, title, watermarkInlineStyle }: BuildExportHtmlDocumentOptions) => string;
11
+ export declare const buildExportHtmlDocument: ({ contentHtml, includeDocumentStyles, printStyle, title, watermarkInlineStyle, mask, }: BuildExportHtmlDocumentOptions) => string;
11
12
  export interface BuildFileViewerRenderedHtmlDocumentOptions {
12
13
  source: HTMLElement;
13
14
  mode?: FileRenderExportMode;
14
15
  title: string;
15
16
  adapter?: FileRenderExportAdapter | null;
16
17
  watermarkInlineStyle?: string;
18
+ mask?: FileViewerPrintMaskOptions | null;
17
19
  }
18
20
  export declare const triggerFileViewerBlobDownload: (blob: Blob, name: string) => void;
19
21
  export declare const triggerFileViewerUrlDownload: (url: string, name: string) => void;
20
22
  export declare const replaceFileViewerCanvasWithImages: (source: HTMLElement, clone: HTMLElement) => void;
21
23
  export declare const waitForFileViewerNextPaint: (targetWindow?: Partial<Pick<Window, "requestAnimationFrame" | "setTimeout">>) => Promise<void>;
22
- export declare const waitForFileViewerImages: (root: ParentNode) => Promise<void>;
24
+ export declare const waitForFileViewerImages: (root: ParentNode | null | undefined) => Promise<void>;
25
+ /**
26
+ * Rewrite ephemeral `blob:` URLs into portable `data:` URLs so exported / printed
27
+ * HTML keeps images after leaving the live viewer document (GitHub #90).
28
+ */
29
+ export declare const inlineFileViewerBlobUrlsInHtml: (html: string) => Promise<string>;
23
30
  export declare const waitForFileViewerPrintWindowReady: (printWindow: Window) => Promise<void>;
24
31
  export declare const resolveFileViewerPrintStyle: (adapter: FileRenderExportAdapter | null, options: FileRenderExportOptions) => Promise<string>;
25
32
  export declare const prepareFileViewerRenderedContentForSnapshot: (source: HTMLElement, adapter?: FileRenderExportAdapter | null) => Promise<void>;
26
- export declare const buildFileViewerRenderedHtmlDocument: ({ source, mode, title, adapter, watermarkInlineStyle }: BuildFileViewerRenderedHtmlDocumentOptions) => Promise<string>;
33
+ export declare const buildFileViewerRenderedHtmlDocument: ({ source, mode, title, adapter, watermarkInlineStyle, mask, }: BuildFileViewerRenderedHtmlDocumentOptions) => Promise<string>;
@@ -1,3 +1,4 @@
1
+ import { buildFileViewerPrintMaskOverlayHtml, FILE_VIEWER_PRINT_MASK_STYLE, normalizeFileViewerPrintMaskOptions, } from '../features/printMask.js';
1
2
  const escapeHtmlAttribute = (value) => value
2
3
  .replace(/&/g, '&amp;')
3
4
  .replace(/"/g, '&quot;')
@@ -9,6 +10,7 @@ const EXPORT_DOCUMENT_STYLE = `
9
10
  body { padding: 24px; }
10
11
  .viewer-export-shell { position: relative; min-height: calc(100vh - 48px); overflow: visible; background: #f2f4f7; }
11
12
  .viewer-export-content { position: relative; z-index: 1; contain: none; width: 100%; min-height: 100%; overflow: visible; }
13
+ .viewer-export-watermark { position: absolute; inset: 0; pointer-events: none; z-index: 20; background-repeat: repeat; print-color-adjust: exact; -webkit-print-color-adjust: exact; }
12
14
  .viewer-export-content .file-render,
13
15
  .viewer-export-content .file-viewer,
14
16
  .viewer-export-content .viewer-stage,
@@ -286,12 +288,14 @@ export const collectDocumentStyles = () => {
286
288
  .filter(Boolean)
287
289
  .join('\n');
288
290
  };
289
- export const buildExportHtmlDocument = ({ contentHtml, includeDocumentStyles = true, printStyle = '', title, watermarkInlineStyle = '' }) => {
291
+ export const buildExportHtmlDocument = ({ contentHtml, includeDocumentStyles = true, printStyle = '', title, watermarkInlineStyle = '', mask = null, }) => {
290
292
  const watermark = watermarkInlineStyle
291
293
  ? `<div class="viewer-export-watermark" style="${watermarkInlineStyle}"></div>`
292
294
  : '';
295
+ const maskHtml = buildFileViewerPrintMaskOverlayHtml(mask);
293
296
  const styles = includeDocumentStyles ? collectDocumentStyles() : '';
294
297
  const printOverrideStyle = printStyle ? `<style data-viewer-print-style>${printStyle}</style>` : '';
298
+ const maskStyle = maskHtml ? `<style data-viewer-print-mask-style>${FILE_VIEWER_PRINT_MASK_STYLE}</style>` : '';
295
299
  const safeTitle = escapeHtmlAttribute(title);
296
300
  return `<!doctype html>
297
301
  <html lang="zh-CN">
@@ -301,10 +305,12 @@ export const buildExportHtmlDocument = ({ contentHtml, includeDocumentStyles = t
301
305
  <title>${safeTitle}</title>
302
306
  ${styles}
303
307
  <style>${EXPORT_DOCUMENT_STYLE}</style>
308
+ ${maskStyle}
304
309
  </head>
305
310
  <body>
306
311
  <main class="viewer-export-shell">
307
312
  <div class="viewer-export-content">${contentHtml}</div>
313
+ ${maskHtml}
308
314
  ${watermark}
309
315
  </main>
310
316
  ${printOverrideStyle}
@@ -371,6 +377,9 @@ export const waitForFileViewerNextPaint = (targetWindow) => {
371
377
  });
372
378
  };
373
379
  export const waitForFileViewerImages = async (root) => {
380
+ if (!root || typeof root.querySelectorAll !== 'function') {
381
+ return;
382
+ }
374
383
  const images = Array.from(root.querySelectorAll('img'));
375
384
  await Promise.all(images.map(async (image) => {
376
385
  if (image.complete) {
@@ -391,6 +400,75 @@ export const waitForFileViewerImages = async (root) => {
391
400
  });
392
401
  }));
393
402
  };
403
+ const bytesToDataUrl = (bytes, mimeType) => {
404
+ const type = mimeType || 'application/octet-stream';
405
+ const nodeBuffer = globalThis.Buffer;
406
+ if (nodeBuffer) {
407
+ return `data:${type};base64,${nodeBuffer.from(bytes).toString('base64')}`;
408
+ }
409
+ let binary = '';
410
+ const view = new Uint8Array(bytes);
411
+ for (let index = 0; index < view.length; index += 1) {
412
+ binary += String.fromCharCode(view[index]);
413
+ }
414
+ return `data:${type};base64,${btoa(binary)}`;
415
+ };
416
+ const blobToDataUrl = async (blob) => {
417
+ if (typeof FileReader === 'function') {
418
+ try {
419
+ return await new Promise((resolve, reject) => {
420
+ const reader = new FileReader();
421
+ reader.onload = () => resolve(String(reader.result || ''));
422
+ reader.onerror = () => reject(reader.error || new Error('Failed to read blob'));
423
+ reader.readAsDataURL(blob);
424
+ });
425
+ }
426
+ catch {
427
+ // Fall through to ArrayBuffer encoding for Node / incomplete FileReader shims.
428
+ }
429
+ }
430
+ return bytesToDataUrl(await blob.arrayBuffer(), blob.type || 'application/octet-stream');
431
+ };
432
+ const collectBlobUrls = (html) => {
433
+ const matches = html.match(/blob:[^\s"'<>)\\]+/g) || [];
434
+ return Array.from(new Set(matches));
435
+ };
436
+ /**
437
+ * Rewrite ephemeral `blob:` URLs into portable `data:` URLs so exported / printed
438
+ * HTML keeps images after leaving the live viewer document (GitHub #90).
439
+ */
440
+ export const inlineFileViewerBlobUrlsInHtml = async (html) => {
441
+ if (!html.includes('blob:') || typeof fetch !== 'function') {
442
+ return html;
443
+ }
444
+ const urls = collectBlobUrls(html);
445
+ if (!urls.length) {
446
+ return html;
447
+ }
448
+ const replacements = await Promise.all(urls.map(async (url) => {
449
+ try {
450
+ const response = await fetch(url);
451
+ if (!response.ok) {
452
+ return null;
453
+ }
454
+ const blob = await response.blob();
455
+ const dataUrl = await blobToDataUrl(blob);
456
+ return dataUrl ? [url, dataUrl] : null;
457
+ }
458
+ catch {
459
+ return null;
460
+ }
461
+ }));
462
+ let next = html;
463
+ for (const pair of replacements) {
464
+ if (!pair) {
465
+ continue;
466
+ }
467
+ const [from, to] = pair;
468
+ next = next.split(from).join(to);
469
+ }
470
+ return next;
471
+ };
394
472
  export const waitForFileViewerPrintWindowReady = async (printWindow) => {
395
473
  const { document: printDocument } = printWindow;
396
474
  if (printDocument.readyState !== 'complete') {
@@ -439,18 +517,21 @@ export const prepareFileViewerRenderedContentForSnapshot = async (source, adapte
439
517
  await waitForFileViewerNextPaint();
440
518
  await waitForFileViewerImages(source);
441
519
  };
442
- export const buildFileViewerRenderedHtmlDocument = async ({ source, mode = 'export', title, adapter = null, watermarkInlineStyle = '' }) => {
520
+ export const buildFileViewerRenderedHtmlDocument = async ({ source, mode = 'export', title, adapter = null, watermarkInlineStyle = '', mask = null, }) => {
443
521
  const exportOptions = { mode, title };
444
522
  const toHtml = adapter === null || adapter === void 0 ? void 0 : adapter.toHtml;
523
+ const normalizedMask = normalizeFileViewerPrintMaskOptions(mask);
445
524
  if (toHtml) {
446
- const contentHtml = await toHtml(exportOptions);
525
+ await prepareFileViewerRenderedContentForSnapshot(source, adapter);
526
+ const contentHtml = await inlineFileViewerBlobUrlsInHtml(await toHtml(exportOptions));
447
527
  const printStyle = await resolveFileViewerPrintStyle(adapter, exportOptions);
448
528
  return buildExportHtmlDocument({
449
529
  contentHtml,
450
530
  includeDocumentStyles: adapter.includeDocumentStyles !== false,
451
531
  printStyle,
452
532
  title,
453
- watermarkInlineStyle
533
+ watermarkInlineStyle,
534
+ mask: normalizedMask,
454
535
  });
455
536
  }
456
537
  await prepareFileViewerRenderedContentForSnapshot(source, adapter);
@@ -459,9 +540,10 @@ export const buildFileViewerRenderedHtmlDocument = async ({ source, mode = 'expo
459
540
  replaceFileViewerCanvasWithImages(source, clone);
460
541
  const printStyle = await resolveFileViewerPrintStyle(adapter, exportOptions);
461
542
  return buildExportHtmlDocument({
462
- contentHtml: clone.innerHTML,
543
+ contentHtml: await inlineFileViewerBlobUrlsInHtml(clone.innerHTML),
463
544
  printStyle,
464
545
  title,
465
- watermarkInlineStyle
546
+ watermarkInlineStyle,
547
+ mask: normalizedMask,
466
548
  });
467
549
  };
@@ -0,0 +1,2 @@
1
+ export { openFileViewerPrintMaskDesigner, } from './features/printMaskDesigner';
2
+ export type { FileViewerPrintMaskDesignerResult, OpenFileViewerPrintMaskDesignerOptions, } from './features/printMaskDesigner';
@@ -0,0 +1 @@
1
+ export { openFileViewerPrintMaskDesigner, } from './features/printMaskDesigner.js';
@@ -26,8 +26,8 @@ const imageStyle = `
26
26
  .image-lightbox[hidden]{display:none}
27
27
  .image-lightbox img{display:block;max-width:100%;max-height:100%;object-fit:contain;background:#fff;box-shadow:0 30px 80px rgba(0,0,0,.4);cursor:zoom-out}
28
28
  .image-lightbox button{position:absolute;top:20px;right:20px;width:40px;height:40px;border:0;border-radius:999px;background:rgba(255,255,255,.92);color:#172033;font-size:24px;line-height:40px;cursor:pointer;box-shadow:0 12px 28px rgba(0,0,0,.18)}
29
- .file-viewer[data-viewer-theme='dark'] .image-viewer{background:#101820}
30
- @media (prefers-color-scheme:dark){.file-viewer[data-viewer-theme='system'] .image-viewer{background:#101820}}
29
+ [data-viewer-theme='dark'] .image-viewer{background:#101820}
30
+ @media (prefers-color-scheme:dark){[data-viewer-theme='system'] .image-viewer{background:#101820}}
31
31
  @media (max-width:767px){.image-stage{padding:12px}.image-lightbox{padding:16px}.image-lightbox button{top:12px;right:12px}}
32
32
  `;
33
33
  const createStyle = (documentRef) => {
@@ -95,8 +95,78 @@ export const hasFileViewerPreviewSource = ({ file, url, } = {}) => {
95
95
  export const resolveFileViewerPreviewRequestReason = (input = {}) => {
96
96
  return hasFileViewerPreviewSource(input) ? 'replace' : 'reset';
97
97
  };
98
+ const FILE_VIEWER_HIERARCHICAL_URL_PATTERN = /^[a-z][a-z0-9+.-]*:\/\//i;
99
+ const FILE_VIEWER_SCHEME_URL_PATTERN = /^[a-z][a-z0-9+.-]*:/i;
100
+ const findFileViewerUrlSuffixIndex = (value) => {
101
+ const queryIndex = value.indexOf('?');
102
+ const hashIndex = value.indexOf('#');
103
+ if (queryIndex === -1) {
104
+ return hashIndex;
105
+ }
106
+ if (hashIndex === -1) {
107
+ return queryIndex;
108
+ }
109
+ return Math.min(queryIndex, hashIndex);
110
+ };
111
+ const encodeFileViewerUrlPathSegment = (segment) => {
112
+ if (!segment) {
113
+ return segment;
114
+ }
115
+ let decoded = segment;
116
+ try {
117
+ decoded = decodeURIComponent(segment);
118
+ }
119
+ catch {
120
+ // Invalid percent escapes are treated as literal filename characters.
121
+ }
122
+ return encodeURIComponent(decoded)
123
+ .replace(/%3A/gi, ':')
124
+ .replace(/%40/gi, '@')
125
+ .replace(/%24/g, '$')
126
+ .replace(/%26/g, '&')
127
+ .replace(/%2B/gi, '+')
128
+ .replace(/%2C/gi, ',')
129
+ .replace(/%3B/gi, ';')
130
+ .replace(/%3D/gi, '=');
131
+ };
132
+ const normalizeFileViewerUrlPathname = (pathname) => {
133
+ return pathname
134
+ .split('/')
135
+ .map(encodeFileViewerUrlPathSegment)
136
+ .join('/');
137
+ };
138
+ const splitFileViewerUrlPathPrefix = (pathPart) => {
139
+ if (pathPart.startsWith('//')) {
140
+ const pathStart = pathPart.indexOf('/', 2);
141
+ return pathStart === -1
142
+ ? { prefix: pathPart, pathname: '' }
143
+ : { prefix: pathPart.slice(0, pathStart), pathname: pathPart.slice(pathStart) };
144
+ }
145
+ const hierarchical = pathPart.match(FILE_VIEWER_HIERARCHICAL_URL_PATTERN);
146
+ if (hierarchical) {
147
+ const pathStart = pathPart.indexOf('/', hierarchical[0].length);
148
+ return pathStart === -1
149
+ ? { prefix: pathPart, pathname: '' }
150
+ : { prefix: pathPart.slice(0, pathStart), pathname: pathPart.slice(pathStart) };
151
+ }
152
+ if (FILE_VIEWER_SCHEME_URL_PATTERN.test(pathPart)) {
153
+ return { prefix: pathPart, pathname: '' };
154
+ }
155
+ return { prefix: '', pathname: pathPart };
156
+ };
98
157
  export const normalizeFileViewerSourceUrl = (sourceUrl) => {
99
- return sourceUrl || null;
158
+ const trimmed = sourceUrl === null || sourceUrl === void 0 ? void 0 : sourceUrl.trim();
159
+ if (!trimmed) {
160
+ return null;
161
+ }
162
+ const suffixIndex = findFileViewerUrlSuffixIndex(trimmed);
163
+ const pathPart = suffixIndex === -1 ? trimmed : trimmed.slice(0, suffixIndex);
164
+ const suffix = suffixIndex === -1 ? '' : trimmed.slice(suffixIndex);
165
+ const { prefix, pathname } = splitFileViewerUrlPathPrefix(pathPart);
166
+ if (!pathname) {
167
+ return `${prefix}${suffix}`;
168
+ }
169
+ return `${prefix}${normalizeFileViewerUrlPathname(pathname)}${suffix}`;
100
170
  };
101
171
  export const createFileViewerEmptyPreviewState = () => {
102
172
  return {
@@ -491,6 +561,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
491
561
  streaming,
492
562
  url,
493
563
  });
564
+ const sourceUrl = remoteSource.url;
494
565
  commitFileViewerLoadStartState({
495
566
  version,
496
567
  filename: remoteSource.filename,
@@ -498,7 +569,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
498
569
  buildState: () => buildLoadStartState({
499
570
  version,
500
571
  source: 'url',
501
- sourceUrl: url,
572
+ sourceUrl,
502
573
  }),
503
574
  onMarkLoadStarted,
504
575
  onLifecycle,
@@ -506,7 +577,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
506
577
  });
507
578
  if (remoteSource.streamPdf) {
508
579
  const stream = await runFileViewerStreamingPdfPreview({
509
- url,
580
+ url: sourceUrl,
510
581
  version,
511
582
  filename: remoteSource.filename,
512
583
  previewTarget,
@@ -516,7 +587,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
516
587
  buildRenderCompleteState: input => buildRenderCompleteState({
517
588
  version: input.version,
518
589
  source: 'url',
519
- sourceUrl: url,
590
+ sourceUrl,
520
591
  }),
521
592
  i18n,
522
593
  onStartLoading,
@@ -559,7 +630,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
559
630
  const controller = requestController.createAbortController();
560
631
  try {
561
632
  const data = await downloadFile({
562
- url,
633
+ url: sourceUrl,
563
634
  signal: controller === null || controller === void 0 ? void 0 : controller.signal,
564
635
  });
565
636
  const download = commitFileViewerRemoteDownloadState({
@@ -595,7 +666,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
595
666
  file: download.source.file,
596
667
  version,
597
668
  source: 'url',
598
- sourceUrl: url,
669
+ sourceUrl,
599
670
  previewTarget,
600
671
  isCurrent,
601
672
  mountRenderedContent,
@@ -604,7 +675,7 @@ export const runFileViewerRemoteFilePreview = async ({ url, version, pageHref, s
604
675
  version: input.version,
605
676
  source: 'url',
606
677
  file: input.file,
607
- sourceUrl: url,
678
+ sourceUrl,
608
679
  }),
609
680
  onSession,
610
681
  onActiveDocumentContext,
@@ -885,10 +956,11 @@ export const resolveFileViewerPageHref = (locationLike) => {
885
956
  return (locationLike === null || locationLike === void 0 ? void 0 : locationLike.href) || undefined;
886
957
  };
887
958
  export const resolveFileViewerRemoteSourcePlan = ({ filename, fallbackFilename = DEFAULT_FILE_VIEWER_SOURCE_FILENAME, pageHref, streaming, url, }) => {
959
+ const sourceUrl = normalizeFileViewerSourceUrl(url) || url;
888
960
  const nextFilename = normalizeFilename(filename || url, fallbackFilename);
889
961
  const extension = getExtension(nextFilename);
890
962
  return {
891
- url,
963
+ url: sourceUrl,
892
964
  filename: nextFilename,
893
965
  extension,
894
966
  streamPdf: pageHref
@@ -896,7 +968,7 @@ export const resolveFileViewerRemoteSourcePlan = ({ filename, fallbackFilename =
896
968
  extension,
897
969
  pageHref,
898
970
  streaming,
899
- url,
971
+ url: sourceUrl,
900
972
  })
901
973
  : false,
902
974
  };
@@ -10,6 +10,7 @@ import { createFileViewerZoomController } from '../features/document/zoom.js';
10
10
  import { createFileViewerViewStateController } from '../features/document/viewState.js';
11
11
  import { createFileViewerFitController, hasFileViewerExplicitInitialViewState, } from '../features/document/fit.js';
12
12
  import { DEFAULT_FILE_VIEWER_DOWNLOAD_FILENAME, DEFAULT_FILE_VIEWER_EXPORT_FILENAME, DEFAULT_FILE_VIEWER_PREVIEW_TITLE, createFileViewerOriginalSourceStateFromNormalizedSource, executeFileViewerDownloadOperation, executeFileViewerExportHtmlOperation, executeFileViewerPrintOperation, resolveFileViewerDisplayFilename, resolveFileViewerOperationFilename, } from './operations.js';
13
+ import { openFileViewerPrintMaskDesignerAsync } from '../features/printMaskLoader.js';
13
14
  import { applyFileViewerZoomAvailability, createUnsupportedAvailability, getRendererAvailability, } from '../registry/capabilities.js';
14
15
  import { buildFileViewerLifecycleContextFromNormalizedSource, buildFileViewerOperationContext, runFileViewerBeforeOperation, runFileViewerLifecycleHook, } from '../lifecycle/operations.js';
15
16
  import { collectFileViewerRendererPlugins, createRendererRegistry, getFileViewerAutoRendererPresetVersion, hasFileViewerRendererPresetName, installFileViewerRendererPlugins, listFileViewerAutoRendererPresets, resolveFileViewerRendererPresetInputs, } from '../registry/registry.js';
@@ -437,7 +438,7 @@ export const createViewer = (container, createOptions = {}) => {
437
438
  await emitLifecycle(options, createOptions.onEvent, 'unload-complete', source, version, startedAt, reason);
438
439
  }
439
440
  };
440
- return {
441
+ const instance = {
441
442
  container,
442
443
  async load(source) {
443
444
  const version = requestScope.requestController.createVersion();
@@ -579,10 +580,27 @@ export const createViewer = (container, createOptions = {}) => {
579
580
  fallback: DEFAULT_FILE_VIEWER_PREVIEW_TITLE,
580
581
  }),
581
582
  watermarkInlineStyle: getWatermarkInlineStyle(printOptions.watermarkInlineStyle),
583
+ mask: printOptions.mask,
582
584
  printAvailable: getCapabilitiesForExtension().print,
583
585
  beforeOperation: runBeforeViewerOperation,
584
586
  });
585
587
  },
588
+ async printWithMask(printOptions = {}) {
589
+ var _a, _b;
590
+ const result = await openFileViewerPrintMaskDesignerAsync({
591
+ root: container,
592
+ i18n: options,
593
+ color: (_a = printOptions.mask) === null || _a === void 0 ? void 0 : _a.color,
594
+ initialRegions: (_b = printOptions.mask) === null || _b === void 0 ? void 0 : _b.regions,
595
+ });
596
+ if (!(result === null || result === void 0 ? void 0 : result.mask)) {
597
+ return;
598
+ }
599
+ await instance.print({
600
+ ...printOptions,
601
+ mask: result.mask,
602
+ });
603
+ },
586
604
  async zoomIn() {
587
605
  fitController.markUserInteraction();
588
606
  const state = await zoomController.zoomIn();
@@ -649,4 +667,5 @@ export const createViewer = (container, createOptions = {}) => {
649
667
  return documentActions.getDocumentTextChunks(textOptions);
650
668
  },
651
669
  };
670
+ return instance;
652
671
  };
@@ -71,12 +71,14 @@ export interface CreateFileViewerOperationActionHandlersInput extends FileViewer
71
71
  export interface FileViewerOperationActionHandlers {
72
72
  downloadOriginalFile(): Promise<boolean | undefined>;
73
73
  exportRenderedHtml(): Promise<string | undefined>;
74
- printRenderedHtml(): Promise<boolean | undefined>;
74
+ printRenderedHtml(options?: FileViewerPrintOptions): Promise<boolean | undefined>;
75
+ printWithMask(options?: FileViewerPrintOptions): Promise<boolean | undefined>;
75
76
  }
76
77
  export interface FileViewerPublicOperationActionHandlers {
77
78
  downloadOriginalFile(): Promise<void>;
78
79
  exportRenderedHtml(): Promise<void>;
79
- printRenderedHtml(): Promise<void>;
80
+ printRenderedHtml(options?: FileViewerPrintOptions): Promise<void>;
81
+ printWithMask(options?: FileViewerPrintOptions): Promise<void>;
80
82
  }
81
83
  export declare const createFileViewerOriginalSourceState: ({ buffer, file, url, filename, mimeType, }?: CreateFileViewerOriginalSourceStateInput) => FileViewerOriginalSourceState;
82
84
  export declare const resolveFileViewerDisplayFilename: (source?: Pick<NormalizedFileViewerSource, "filename"> | null, fallback?: string) => string;
@@ -61,7 +61,7 @@ const runBeforeOperation = async (beforeOperation, operation) => {
61
61
  }
62
62
  return await beforeOperation(operation);
63
63
  };
64
- const buildRenderedHtmlDocumentFromOperation = async (mode, { source, title, filename, adapter = null, watermarkInlineStyle, i18n, }) => {
64
+ const buildRenderedHtmlDocumentFromOperation = async (mode, { source, title, filename, adapter = null, watermarkInlineStyle, mask = null, i18n, }) => {
65
65
  if (!source) {
66
66
  throw new Error(translateFileViewerMessage(i18n, 'error.noExportContent'));
67
67
  }
@@ -74,6 +74,7 @@ const buildRenderedHtmlDocumentFromOperation = async (mode, { source, title, fil
74
74
  }),
75
75
  adapter,
76
76
  watermarkInlineStyle,
77
+ mask: mode === 'print' ? mask : null,
77
78
  });
78
79
  };
79
80
  export const executeFileViewerDownloadOperation = async ({ source, filename, beforeOperation, i18n, throwOnMissingSource = true, }) => {
@@ -222,12 +223,51 @@ export const createFileViewerOperationActionHandlers = ({ getBuffer, getFile, ge
222
223
  return undefined;
223
224
  }
224
225
  },
225
- async printRenderedHtml() {
226
- var _a;
226
+ async printRenderedHtml(options = {}) {
227
+ var _a, _b, _c;
227
228
  try {
228
229
  return await executeFileViewerPrintOperation({
229
230
  ...getRenderedOperationInput(),
230
- printAvailable: (_a = getPrintAvailable === null || getPrintAvailable === void 0 ? void 0 : getPrintAvailable()) !== null && _a !== void 0 ? _a : true,
231
+ ...options,
232
+ watermarkInlineStyle: (_b = (_a = options.watermarkInlineStyle) !== null && _a !== void 0 ? _a : getWatermarkInlineStyle === null || getWatermarkInlineStyle === void 0 ? void 0 : getWatermarkInlineStyle()) !== null && _b !== void 0 ? _b : undefined,
233
+ printAvailable: (_c = getPrintAvailable === null || getPrintAvailable === void 0 ? void 0 : getPrintAvailable()) !== null && _c !== void 0 ? _c : true,
234
+ });
235
+ }
236
+ catch (error) {
237
+ handleFileViewerOperationActionError('print', error, {
238
+ errorPrefixes,
239
+ formatErrorMessage,
240
+ getI18n,
241
+ i18n,
242
+ onError,
243
+ onErrorMessage,
244
+ });
245
+ return undefined;
246
+ }
247
+ },
248
+ async printWithMask(options = {}) {
249
+ var _a, _b, _c, _d, _e;
250
+ try {
251
+ const source = getRenderedSource();
252
+ if (!source) {
253
+ throw new Error(translateFileViewerMessage(resolveI18n(), 'error.noExportContent'));
254
+ }
255
+ const { openFileViewerPrintMaskDesignerAsync } = await import('../features/printMaskLoader.js');
256
+ const result = await openFileViewerPrintMaskDesignerAsync({
257
+ root: source,
258
+ i18n: resolveI18n(),
259
+ color: (_a = options.mask) === null || _a === void 0 ? void 0 : _a.color,
260
+ initialRegions: (_b = options.mask) === null || _b === void 0 ? void 0 : _b.regions,
261
+ });
262
+ if (!(result === null || result === void 0 ? void 0 : result.mask)) {
263
+ return undefined;
264
+ }
265
+ return await executeFileViewerPrintOperation({
266
+ ...getRenderedOperationInput(),
267
+ ...options,
268
+ watermarkInlineStyle: (_d = (_c = options.watermarkInlineStyle) !== null && _c !== void 0 ? _c : getWatermarkInlineStyle === null || getWatermarkInlineStyle === void 0 ? void 0 : getWatermarkInlineStyle()) !== null && _d !== void 0 ? _d : undefined,
269
+ mask: result.mask,
270
+ printAvailable: (_e = getPrintAvailable === null || getPrintAvailable === void 0 ? void 0 : getPrintAvailable()) !== null && _e !== void 0 ? _e : true,
231
271
  });
232
272
  }
233
273
  catch (error) {
@@ -253,8 +293,11 @@ export const createFileViewerPublicOperationActionHandlers = (input) => {
253
293
  async exportRenderedHtml() {
254
294
  await actions.exportRenderedHtml();
255
295
  },
256
- async printRenderedHtml() {
257
- await actions.printRenderedHtml();
296
+ async printRenderedHtml(options) {
297
+ await actions.printRenderedHtml(options);
298
+ },
299
+ async printWithMask(options) {
300
+ await actions.printWithMask(options);
258
301
  },
259
302
  };
260
303
  };
package/headless.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/headless';
package/headless.js ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/headless.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/core",
3
- "version": "2.1.22",
3
+ "version": "2.1.24",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Framework-neutral modular TypeScript core for Flyfish File Viewer renderer orchestration, lifecycle APIs, search, zoom, print, and export",
@@ -62,10 +62,23 @@
62
62
  "import": "./dist/browser.js",
63
63
  "default": "./dist/browser.js"
64
64
  },
65
+ "./print-mask": {
66
+ "types": "./dist/print-mask.d.ts",
67
+ "import": "./dist/print-mask.js",
68
+ "default": "./dist/print-mask.js"
69
+ },
65
70
  "./package.json": "./package.json"
66
71
  },
67
72
  "files": [
73
+ "assets.js",
74
+ "assets.d.ts",
75
+ "browser.js",
76
+ "browser.d.ts",
68
77
  "dist",
78
+ "headless.js",
79
+ "headless.d.ts",
80
+ "print-mask.js",
81
+ "print-mask.d.ts",
69
82
  "vendor",
70
83
  "README.md",
71
84
  "README.en.md",
@@ -0,0 +1 @@
1
+ export * from './dist/print-mask';
package/print-mask.js ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/print-mask.js';