@file-viewer/core 2.0.0
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/LICENSE +160 -0
- package/README.en.md +78 -0
- package/README.md +83 -0
- package/dist/assets.d.ts +62 -0
- package/dist/assets.js +260 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/capabilities.d.ts +24 -0
- package/dist/capabilities.js +95 -0
- package/dist/document.d.ts +9 -0
- package/dist/document.js +86 -0
- package/dist/documentDom/anchors.d.ts +7 -0
- package/dist/documentDom/anchors.js +196 -0
- package/dist/documentDom/index.d.ts +5 -0
- package/dist/documentDom/index.js +3 -0
- package/dist/documentDom/providers.d.ts +13 -0
- package/dist/documentDom/providers.js +52 -0
- package/dist/documentDom/scroll.d.ts +12 -0
- package/dist/documentDom/scroll.js +42 -0
- package/dist/documentDom.d.ts +5 -0
- package/dist/documentDom.js +3 -0
- package/dist/documentEvents.d.ts +73 -0
- package/dist/documentEvents.js +150 -0
- package/dist/documentSearch.d.ts +50 -0
- package/dist/documentSearch.js +459 -0
- package/dist/documentZoom.d.ts +47 -0
- package/dist/documentZoom.js +184 -0
- package/dist/export.d.ts +26 -0
- package/dist/export.js +466 -0
- package/dist/formats.d.ts +305 -0
- package/dist/formats.js +207 -0
- package/dist/headless.d.ts +25 -0
- package/dist/headless.js +14 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.js +118 -0
- package/dist/lifecycleFacade.d.ts +46 -0
- package/dist/lifecycleFacade.js +68 -0
- package/dist/loading.d.ts +59 -0
- package/dist/loading.js +489 -0
- package/dist/operations.d.ts +287 -0
- package/dist/operations.js +485 -0
- package/dist/options.d.ts +16 -0
- package/dist/options.js +92 -0
- package/dist/presentation.d.ts +14 -0
- package/dist/presentation.js +16 -0
- package/dist/printLayout.d.ts +19 -0
- package/dist/printLayout.js +83 -0
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +63 -0
- package/dist/rendererDispatcher.d.ts +21 -0
- package/dist/rendererDispatcher.js +42 -0
- package/dist/rendererHandler.d.ts +165 -0
- package/dist/rendererHandler.js +354 -0
- package/dist/renderers/archive.d.ts +2 -0
- package/dist/renderers/archive.js +547 -0
- package/dist/renderers/archiveCache.d.ts +10 -0
- package/dist/renderers/archiveCache.js +96 -0
- package/dist/renderers/archiveFallback.d.ts +7 -0
- package/dist/renderers/archiveFallback.js +166 -0
- package/dist/renderers/archiveShared.d.ts +23 -0
- package/dist/renderers/archiveShared.js +71 -0
- package/dist/renderers/audio.d.ts +8 -0
- package/dist/renderers/audio.js +219 -0
- package/dist/renderers/cad.d.ts +2 -0
- package/dist/renderers/cad.js +445 -0
- package/dist/renderers/code.d.ts +11 -0
- package/dist/renderers/code.js +233 -0
- package/dist/renderers/data.d.ts +7 -0
- package/dist/renderers/data.js +370 -0
- package/dist/renderers/drawing.d.ts +10 -0
- package/dist/renderers/drawing.js +537 -0
- package/dist/renderers/eda.d.ts +2 -0
- package/dist/renderers/eda.js +434 -0
- package/dist/renderers/edaParser.d.ts +77 -0
- package/dist/renderers/edaParser.js +569 -0
- package/dist/renderers/email.d.ts +2 -0
- package/dist/renderers/email.js +463 -0
- package/dist/renderers/epub.d.ts +2 -0
- package/dist/renderers/epub.js +330 -0
- package/dist/renderers/geo.d.ts +2 -0
- package/dist/renderers/geo.js +284 -0
- package/dist/renderers/image.d.ts +2 -0
- package/dist/renderers/image.js +179 -0
- package/dist/renderers/index.d.ts +21 -0
- package/dist/renderers/index.js +207 -0
- package/dist/renderers/markdown.d.ts +2 -0
- package/dist/renderers/markdown.js +83 -0
- package/dist/renderers/model.d.ts +2 -0
- package/dist/renderers/model.js +566 -0
- package/dist/renderers/ofd.d.ts +2 -0
- package/dist/renderers/ofd.js +255 -0
- package/dist/renderers/openDocument.d.ts +2 -0
- package/dist/renderers/openDocument.js +122 -0
- package/dist/renderers/pdf.d.ts +3 -0
- package/dist/renderers/pdf.js +846 -0
- package/dist/renderers/pdfStyles.d.ts +1 -0
- package/dist/renderers/pdfStyles.js +1 -0
- package/dist/renderers/pptx.d.ts +2 -0
- package/dist/renderers/pptx.js +202 -0
- package/dist/renderers/spreadsheet/state.d.ts +80 -0
- package/dist/renderers/spreadsheet/state.js +96 -0
- package/dist/renderers/spreadsheet/view.d.ts +25 -0
- package/dist/renderers/spreadsheet/view.js +833 -0
- package/dist/renderers/spreadsheet/worker/index.d.ts +2 -0
- package/dist/renderers/spreadsheet/worker/index.js +1 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.d.ts +73 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.js +623 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/color.d.ts +2 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/color.js +73 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/index.d.ts +1 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/index.js +1 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/parser.d.ts +18 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/parser.js +106 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.d.ts +1 -0
- package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.js +11 -0
- package/dist/renderers/spreadsheet/worker/type.d.ts +57 -0
- package/dist/renderers/spreadsheet/worker/type.js +1 -0
- package/dist/renderers/spreadsheet.d.ts +3 -0
- package/dist/renderers/spreadsheet.js +929 -0
- package/dist/renderers/typst.d.ts +8 -0
- package/dist/renderers/typst.js +415 -0
- package/dist/renderers/umd/parser.d.ts +30 -0
- package/dist/renderers/umd/parser.js +408 -0
- package/dist/renderers/umd.d.ts +2 -0
- package/dist/renderers/umd.js +297 -0
- package/dist/renderers/video.d.ts +8 -0
- package/dist/renderers/video.js +108 -0
- package/dist/renderers/wordDoc.d.ts +5 -0
- package/dist/renderers/wordDoc.js +284 -0
- package/dist/renderers/wordDocx.d.ts +5 -0
- package/dist/renderers/wordDocx.js +501 -0
- package/dist/renderers/wordDocx.worker.d.ts +1 -0
- package/dist/renderers/wordDocx.worker.js +96 -0
- package/dist/source.d.ts +18 -0
- package/dist/source.js +152 -0
- package/dist/sourceLoading.d.ts +566 -0
- package/dist/sourceLoading.js +918 -0
- package/dist/state.d.ts +16 -0
- package/dist/state.js +81 -0
- package/dist/types.d.ts +446 -0
- package/dist/types.js +1 -0
- package/dist/viewer.d.ts +8 -0
- package/dist/viewer.js +285 -0
- package/dist/viewerOperations.d.ts +88 -0
- package/dist/viewerOperations.js +242 -0
- package/dist/watermark.d.ts +15 -0
- package/dist/watermark.js +81 -0
- package/dist/worker.d.ts +34 -0
- package/dist/worker.js +101 -0
- package/package.json +109 -0
- package/vendor/ofd/dltech/jbig2/arithmetic_decoder.js +183 -0
- package/vendor/ofd/dltech/jbig2/ccitt.js +1070 -0
- package/vendor/ofd/dltech/jbig2/compatibility.js +12 -0
- package/vendor/ofd/dltech/jbig2/core_utils.js +180 -0
- package/vendor/ofd/dltech/jbig2/is_node.js +27 -0
- package/vendor/ofd/dltech/jbig2/jbig2.js +2589 -0
- package/vendor/ofd/dltech/jbig2/jbig2_stream.js +81 -0
- package/vendor/ofd/dltech/jbig2/primitives.js +387 -0
- package/vendor/ofd/dltech/jbig2/stream.js +1348 -0
- package/vendor/ofd/dltech/jbig2/util.js +972 -0
- package/vendor/ofd/dltech/ofd/ofd.d.ts +11 -0
- package/vendor/ofd/dltech/ofd/ofd.js +100 -0
- package/vendor/ofd/dltech/ofd/ofd_parser.js +395 -0
- package/vendor/ofd/dltech/ofd/ofd_render.js +473 -0
- package/vendor/ofd/dltech/ofd/ofd_util.js +350 -0
- package/vendor/ofd/dltech/ofd/pipeline.js +26 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { registerFileViewerZoomProvider, unregisterFileViewerZoomProvider, } from '../documentDom.js';
|
|
2
|
+
import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter } from '../documentZoom.js';
|
|
3
|
+
const imageMimeMap = {
|
|
4
|
+
avif: 'image/avif',
|
|
5
|
+
bmp: 'image/bmp',
|
|
6
|
+
gif: 'image/gif',
|
|
7
|
+
heic: 'image/heic',
|
|
8
|
+
heif: 'image/heif',
|
|
9
|
+
ico: 'image/x-icon',
|
|
10
|
+
jxl: 'image/jxl',
|
|
11
|
+
jpg: 'image/jpeg',
|
|
12
|
+
jpeg: 'image/jpeg',
|
|
13
|
+
png: 'image/png',
|
|
14
|
+
svg: 'image/svg+xml',
|
|
15
|
+
tif: 'image/tiff',
|
|
16
|
+
tiff: 'image/tiff',
|
|
17
|
+
webp: 'image/webp',
|
|
18
|
+
};
|
|
19
|
+
const imageStyle = `
|
|
20
|
+
.image-viewer{position:relative;width:100%;height:100%;overflow:auto;background:#eef1f4;box-sizing:border-box}
|
|
21
|
+
.image-stage{min-width:100%;min-height:100%;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box}
|
|
22
|
+
.image-stage img{display:block;width:auto;max-width:none;margin:0 auto;border:0;box-shadow:0 18px 48px rgba(15,23,42,.16);background:#fff;cursor:zoom-in}
|
|
23
|
+
.image-lightbox{position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;padding:40px;background:rgba(15,23,42,.88);box-sizing:border-box}
|
|
24
|
+
.image-lightbox[hidden]{display:none}
|
|
25
|
+
.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}
|
|
26
|
+
.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)}
|
|
27
|
+
.file-viewer[data-viewer-theme='dark'] .image-viewer{background:#101820}
|
|
28
|
+
@media (prefers-color-scheme:dark){.file-viewer[data-viewer-theme='system'] .image-viewer{background:#101820}}
|
|
29
|
+
@media (max-width:767px){.image-stage{padding:12px}.image-lightbox{padding:16px}.image-lightbox button{top:12px;right:12px}}
|
|
30
|
+
`;
|
|
31
|
+
const createStyle = () => {
|
|
32
|
+
const style = document.createElement('style');
|
|
33
|
+
style.textContent = imageStyle;
|
|
34
|
+
return style;
|
|
35
|
+
};
|
|
36
|
+
const getImageBlobType = (type) => {
|
|
37
|
+
const normalized = (type || '').trim().toLowerCase();
|
|
38
|
+
return imageMimeMap[normalized] || 'image/*';
|
|
39
|
+
};
|
|
40
|
+
const readBlobDataUrl = async (blob) => {
|
|
41
|
+
return await new Promise((resolve, reject) => {
|
|
42
|
+
const reader = new FileReader();
|
|
43
|
+
reader.onload = event => {
|
|
44
|
+
var _a;
|
|
45
|
+
const result = (_a = event.target) === null || _a === void 0 ? void 0 : _a.result;
|
|
46
|
+
if (typeof result === 'string') {
|
|
47
|
+
resolve(result);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
reject(new Error('Unable to read image data URL.'));
|
|
51
|
+
};
|
|
52
|
+
reader.onerror = () => reject(reader.error || new Error('Unable to read image data URL.'));
|
|
53
|
+
reader.readAsDataURL(blob);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const renderHeic = async (buffer, type) => {
|
|
57
|
+
const { default: heic2any } = await import('heic2any');
|
|
58
|
+
const result = await heic2any({
|
|
59
|
+
blob: new Blob([buffer], { type: getImageBlobType(type) }),
|
|
60
|
+
toType: 'image/png',
|
|
61
|
+
});
|
|
62
|
+
const blob = Array.isArray(result) ? result[0] : result;
|
|
63
|
+
return readBlobDataUrl(blob);
|
|
64
|
+
};
|
|
65
|
+
const resolveImageUrl = async (buffer, type) => {
|
|
66
|
+
const normalizedType = (type || '').trim().toLowerCase();
|
|
67
|
+
if (normalizedType === 'heic' || normalizedType === 'heif') {
|
|
68
|
+
return renderHeic(buffer, normalizedType);
|
|
69
|
+
}
|
|
70
|
+
return readBlobDataUrl(new Blob([buffer], { type: getImageBlobType(normalizedType) }));
|
|
71
|
+
};
|
|
72
|
+
const clampZoom = (value) => {
|
|
73
|
+
return Math.min(5, Math.max(0.1, Number(value.toFixed(2))));
|
|
74
|
+
};
|
|
75
|
+
const applyImageZoom = (image, viewportHeight, zoom) => {
|
|
76
|
+
if (viewportHeight > 0) {
|
|
77
|
+
image.style.height = `${Math.max(1, Math.round(viewportHeight * zoom))}px`;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
image.style.height = `${zoom * 100}%`;
|
|
81
|
+
};
|
|
82
|
+
const createLightbox = (src) => {
|
|
83
|
+
const lightbox = document.createElement('div');
|
|
84
|
+
lightbox.className = 'image-lightbox';
|
|
85
|
+
lightbox.hidden = true;
|
|
86
|
+
lightbox.setAttribute('role', 'dialog');
|
|
87
|
+
lightbox.setAttribute('aria-modal', 'true');
|
|
88
|
+
const image = document.createElement('img');
|
|
89
|
+
image.alt = 'Preview image';
|
|
90
|
+
image.src = src;
|
|
91
|
+
const closeButton = document.createElement('button');
|
|
92
|
+
closeButton.type = 'button';
|
|
93
|
+
closeButton.setAttribute('aria-label', 'Close image preview');
|
|
94
|
+
closeButton.textContent = 'x';
|
|
95
|
+
const close = () => {
|
|
96
|
+
lightbox.hidden = true;
|
|
97
|
+
};
|
|
98
|
+
closeButton.addEventListener('click', close);
|
|
99
|
+
image.addEventListener('click', close);
|
|
100
|
+
lightbox.addEventListener('click', event => {
|
|
101
|
+
if (event.target === lightbox) {
|
|
102
|
+
close();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
lightbox.append(image, closeButton);
|
|
106
|
+
return {
|
|
107
|
+
element: lightbox,
|
|
108
|
+
open() {
|
|
109
|
+
lightbox.hidden = false;
|
|
110
|
+
},
|
|
111
|
+
destroy() {
|
|
112
|
+
closeButton.removeEventListener('click', close);
|
|
113
|
+
image.removeEventListener('click', close);
|
|
114
|
+
lightbox.remove();
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
export default async function renderImage(buffer, target, type) {
|
|
119
|
+
const src = await resolveImageUrl(buffer, type);
|
|
120
|
+
let zoom = 1;
|
|
121
|
+
let viewportHeight = 0;
|
|
122
|
+
const zoomEmitter = createZoomChangeEmitter();
|
|
123
|
+
const root = document.createElement('div');
|
|
124
|
+
root.className = 'image-viewer';
|
|
125
|
+
root.dataset.viewerZoomProvider = 'image';
|
|
126
|
+
const stage = document.createElement('div');
|
|
127
|
+
stage.className = 'image-stage';
|
|
128
|
+
const image = document.createElement('img');
|
|
129
|
+
image.alt = '图片';
|
|
130
|
+
image.src = src;
|
|
131
|
+
stage.append(image);
|
|
132
|
+
root.append(stage);
|
|
133
|
+
const lightbox = createLightbox(src);
|
|
134
|
+
const openLightbox = () => lightbox.open();
|
|
135
|
+
image.addEventListener('click', openLightbox);
|
|
136
|
+
document.body.append(lightbox.element);
|
|
137
|
+
const updateViewportSize = () => {
|
|
138
|
+
viewportHeight = root.clientHeight || 0;
|
|
139
|
+
applyImageZoom(image, viewportHeight, zoom);
|
|
140
|
+
zoomEmitter.emit();
|
|
141
|
+
};
|
|
142
|
+
const resizeObserver = new ResizeObserver(updateViewportSize);
|
|
143
|
+
resizeObserver.observe(root);
|
|
144
|
+
const getZoomState = () => ({
|
|
145
|
+
scale: zoom,
|
|
146
|
+
label: `${Math.round(zoom * 100)}%`,
|
|
147
|
+
canZoomIn: zoom < 5,
|
|
148
|
+
canZoomOut: zoom > 0.1,
|
|
149
|
+
canReset: zoom !== 1,
|
|
150
|
+
minScale: 0.1,
|
|
151
|
+
maxScale: 5,
|
|
152
|
+
});
|
|
153
|
+
const setZoom = (scale) => {
|
|
154
|
+
zoom = clampZoom(scale);
|
|
155
|
+
applyImageZoom(image, viewportHeight, zoom);
|
|
156
|
+
zoomEmitter.emit();
|
|
157
|
+
return getZoomState();
|
|
158
|
+
};
|
|
159
|
+
registerFileViewerZoomProvider(root, {
|
|
160
|
+
zoomIn: () => setZoom(zoom + 0.15),
|
|
161
|
+
zoomOut: () => setZoom(zoom - 0.15),
|
|
162
|
+
resetZoom: () => setZoom(1),
|
|
163
|
+
setZoom,
|
|
164
|
+
getState: getZoomState,
|
|
165
|
+
subscribe: zoomEmitter.subscribe,
|
|
166
|
+
});
|
|
167
|
+
target.replaceChildren(createStyle(), root);
|
|
168
|
+
updateViewportSize();
|
|
169
|
+
return {
|
|
170
|
+
$el: target,
|
|
171
|
+
unmount() {
|
|
172
|
+
unregisterFileViewerZoomProvider(root);
|
|
173
|
+
resizeObserver.disconnect();
|
|
174
|
+
image.removeEventListener('click', openLightbox);
|
|
175
|
+
lightbox.destroy();
|
|
176
|
+
target.replaceChildren();
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FileRenderHandler, FileViewerRenderedInstance } from '../types';
|
|
2
|
+
type CoreBrowserRendererHandler = FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>;
|
|
3
|
+
interface CoreBrowserRendererHandlerEntry {
|
|
4
|
+
rendererId: string;
|
|
5
|
+
handler: CoreBrowserRendererHandler;
|
|
6
|
+
}
|
|
7
|
+
export declare const coreBrowserRendererHandlers: readonly CoreBrowserRendererHandlerEntry[];
|
|
8
|
+
export declare const createFileViewerCoreRendererRegistry: () => {
|
|
9
|
+
dispatcher: import("..").FileViewerRendererDispatcher<CoreBrowserRendererHandler>;
|
|
10
|
+
registry: import("..").RendererRegistry;
|
|
11
|
+
missingRendererIds: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare const fileViewerCoreRendererRegistryBridge: {
|
|
14
|
+
dispatcher: import("..").FileViewerRendererDispatcher<CoreBrowserRendererHandler>;
|
|
15
|
+
registry: import("..").RendererRegistry;
|
|
16
|
+
missingRendererIds: string[];
|
|
17
|
+
};
|
|
18
|
+
export declare const fileViewerCoreRendererRegistry: import("..").RendererRegistry;
|
|
19
|
+
export declare const fileViewerCoreRendererDispatcher: import("..").FileViewerRendererDispatcher<CoreBrowserRendererHandler>;
|
|
20
|
+
export declare const missingFileViewerCoreRendererHandlers: string[];
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { DEFAULT_RENDERER_DEFINITIONS } from '../formats.js';
|
|
2
|
+
import { createFileRenderHandlerRegistry } from '../rendererHandler.js';
|
|
3
|
+
import { createFileViewerRendererDispatcher } from '../rendererDispatcher.js';
|
|
4
|
+
import { createFileViewerUnsupportedState } from '../state.js';
|
|
5
|
+
const createWrapper = (el) => ({
|
|
6
|
+
$el: el,
|
|
7
|
+
unmount() {
|
|
8
|
+
// DOM renderers clean themselves up through their own returned instance.
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
export const coreBrowserRendererHandlers = [
|
|
12
|
+
{
|
|
13
|
+
rendererId: 'code',
|
|
14
|
+
handler: async (buffer, target, type) => {
|
|
15
|
+
const { default: renderCode } = await import('./code.js');
|
|
16
|
+
return renderCode(buffer, target, type);
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
rendererId: 'markdown',
|
|
21
|
+
handler: async (buffer, target) => {
|
|
22
|
+
const { default: renderMarkdown } = await import('./markdown.js');
|
|
23
|
+
return renderMarkdown(buffer, target);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
rendererId: 'video',
|
|
28
|
+
handler: async (buffer, target, type, context) => {
|
|
29
|
+
const { default: renderVideo } = await import('./video.js');
|
|
30
|
+
return renderVideo(buffer, target, type, context);
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
rendererId: 'audio',
|
|
35
|
+
handler: async (buffer, target, type) => {
|
|
36
|
+
const { default: renderAudio } = await import('./audio.js');
|
|
37
|
+
return renderAudio(buffer, target, type);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
rendererId: 'image',
|
|
42
|
+
handler: async (buffer, target, type) => {
|
|
43
|
+
const { default: renderImage } = await import('./image.js');
|
|
44
|
+
return renderImage(buffer, target, type);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
rendererId: 'umd',
|
|
49
|
+
handler: async (buffer, target) => {
|
|
50
|
+
const { default: renderUmd } = await import('./umd.js');
|
|
51
|
+
return renderUmd(buffer, target);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
rendererId: 'geo',
|
|
56
|
+
handler: async (buffer, target, type) => {
|
|
57
|
+
const { default: renderGeo } = await import('./geo.js');
|
|
58
|
+
return renderGeo(buffer, target, type);
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
rendererId: 'open-document',
|
|
63
|
+
handler: async (buffer, target, type) => {
|
|
64
|
+
const { default: renderOpenDocument } = await import('./openDocument.js');
|
|
65
|
+
return renderOpenDocument(buffer, target, type);
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
rendererId: 'ofd',
|
|
70
|
+
handler: async (buffer, target, _type, context) => {
|
|
71
|
+
const { default: renderOfd } = await import('./ofd.js');
|
|
72
|
+
return renderOfd(buffer, target, context);
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
rendererId: 'pdf',
|
|
77
|
+
handler: async (buffer, target, _type, context) => {
|
|
78
|
+
const { default: renderPdf } = await import('./pdf.js');
|
|
79
|
+
return renderPdf(buffer, target, context);
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
rendererId: 'office-word-openxml',
|
|
84
|
+
handler: async (buffer, target, _type, context) => {
|
|
85
|
+
const { default: renderWordDocx } = await import('./wordDocx.js');
|
|
86
|
+
return renderWordDocx(buffer, target, context);
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
rendererId: 'office-word-binary',
|
|
91
|
+
handler: async (buffer, target, _type, context) => {
|
|
92
|
+
const { default: renderWordDoc } = await import('./wordDoc.js');
|
|
93
|
+
return renderWordDoc(buffer, target, context);
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
rendererId: 'spreadsheet-openxml',
|
|
98
|
+
handler: async (buffer, target, type, context) => {
|
|
99
|
+
const { default: renderSpreadsheet } = await import('./spreadsheet.js');
|
|
100
|
+
return renderSpreadsheet(buffer, target, type, context);
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
rendererId: 'email',
|
|
105
|
+
handler: async (buffer, target, type, context) => {
|
|
106
|
+
const { default: renderEmail } = await import('./email.js');
|
|
107
|
+
return renderEmail(buffer, target, type, context);
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
rendererId: 'eda',
|
|
112
|
+
handler: async (buffer, target, type, context) => {
|
|
113
|
+
const { default: renderEda } = await import('./eda.js');
|
|
114
|
+
return renderEda(buffer, target, type, context);
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
rendererId: 'cad',
|
|
119
|
+
handler: async (buffer, target, type, context) => {
|
|
120
|
+
const { default: renderCad } = await import('./cad.js');
|
|
121
|
+
return renderCad(buffer, target, type, context);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
rendererId: 'typst',
|
|
126
|
+
handler: async (buffer, target, type, context) => {
|
|
127
|
+
const { default: renderTypst } = await import('./typst.js');
|
|
128
|
+
return renderTypst(buffer, target, type, context);
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
rendererId: 'office-presentation',
|
|
133
|
+
handler: async (buffer, target, type, context) => {
|
|
134
|
+
const { default: renderPptx } = await import('./pptx.js');
|
|
135
|
+
return renderPptx(buffer, target, type, context);
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
rendererId: 'epub',
|
|
140
|
+
handler: async (buffer, target) => {
|
|
141
|
+
const { default: renderEpub } = await import('./epub.js');
|
|
142
|
+
return renderEpub(buffer, target);
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
rendererId: 'model',
|
|
147
|
+
handler: async (buffer, target, type, context) => {
|
|
148
|
+
const { default: renderModel } = await import('./model.js');
|
|
149
|
+
return renderModel(buffer, target, type, context);
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
rendererId: 'drawing',
|
|
154
|
+
handler: async (buffer, target, type, context) => {
|
|
155
|
+
const { default: renderDrawing } = await import('./drawing.js');
|
|
156
|
+
return renderDrawing(buffer, target, type, context);
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
rendererId: 'data-asset',
|
|
161
|
+
handler: async (buffer, target, type, context) => {
|
|
162
|
+
const { default: renderDataAsset } = await import('./data.js');
|
|
163
|
+
return renderDataAsset(buffer, target, type, context);
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
rendererId: 'archive',
|
|
168
|
+
handler: async (buffer, target, type, context) => {
|
|
169
|
+
const { default: renderArchive } = await import('./archive.js');
|
|
170
|
+
return renderArchive(buffer, target, type, context);
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
const renderUnsupported = async (_buffer, target, type) => {
|
|
175
|
+
const state = createFileViewerUnsupportedState(type);
|
|
176
|
+
const wrapper = document.createElement('div');
|
|
177
|
+
wrapper.style.textAlign = 'center';
|
|
178
|
+
wrapper.style.marginTop = '80px';
|
|
179
|
+
const message = document.createElement('div');
|
|
180
|
+
message.textContent = state.message;
|
|
181
|
+
wrapper.appendChild(message);
|
|
182
|
+
if (state.description) {
|
|
183
|
+
const description = document.createElement('div');
|
|
184
|
+
description.textContent = state.description;
|
|
185
|
+
wrapper.appendChild(description);
|
|
186
|
+
}
|
|
187
|
+
target.replaceChildren(wrapper);
|
|
188
|
+
return createWrapper(target);
|
|
189
|
+
};
|
|
190
|
+
export const createFileViewerCoreRendererRegistry = () => {
|
|
191
|
+
const bridge = createFileRenderHandlerRegistry({
|
|
192
|
+
definitions: DEFAULT_RENDERER_DEFINITIONS,
|
|
193
|
+
handlers: coreBrowserRendererHandlers,
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
...bridge,
|
|
197
|
+
dispatcher: createFileViewerRendererDispatcher({
|
|
198
|
+
registry: bridge.registry,
|
|
199
|
+
handlers: coreBrowserRendererHandlers,
|
|
200
|
+
fallbackHandler: renderUnsupported,
|
|
201
|
+
}),
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
export const fileViewerCoreRendererRegistryBridge = createFileViewerCoreRendererRegistry();
|
|
205
|
+
export const fileViewerCoreRendererRegistry = fileViewerCoreRendererRegistryBridge.registry;
|
|
206
|
+
export const fileViewerCoreRendererDispatcher = fileViewerCoreRendererRegistryBridge.dispatcher;
|
|
207
|
+
export const missingFileViewerCoreRendererHandlers = fileViewerCoreRendererRegistryBridge.missingRendererIds;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { marked } from 'marked';
|
|
2
|
+
import { createFileViewerZoomChangeEmitter as createZoomChangeEmitter } from '../documentZoom.js';
|
|
3
|
+
import { registerFileViewerZoomProvider, unregisterFileViewerZoomProvider, } from '../documentDom.js';
|
|
4
|
+
import { readFileViewerText as readText } from '../source.js';
|
|
5
|
+
const markdownStyle = `
|
|
6
|
+
.markdown-viewer{min-height:100%;padding:28px 16px 48px;background:#eef1f4;overflow:auto;box-sizing:border-box}
|
|
7
|
+
.markdown-body{color-scheme:light;--bgColor-default:#fff;--bgColor-muted:#f6f8fa;--bgColor-neutral-muted:#818b981f;--borderColor-default:#d1d9e0;--borderColor-muted:#d1d9e0b3;--borderColor-neutral-muted:#d1d9e0b3;--fgColor-default:#1f2328;--fgColor-muted:#59636e;--fgColor-accent:#0969da;background:var(--bgColor-default);border:1px solid rgba(20,35,53,.1);border-radius:12px;margin:0 auto;box-sizing:border-box;min-width:200px;max-width:var(--markdown-max-width,980px);padding:var(--markdown-padding,45px);color:var(--fgColor-default);font-size:var(--markdown-font-size,16px);box-shadow:0 18px 42px rgba(15,23,42,.1)}
|
|
8
|
+
.markdown-body h1,.markdown-body h2,.markdown-body h3{margin-top:24px;margin-bottom:16px;font-weight:700;line-height:1.25}
|
|
9
|
+
.markdown-body h1{padding-bottom:.3em;border-bottom:1px solid var(--borderColor-muted);font-size:2em}
|
|
10
|
+
.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid var(--borderColor-muted);font-size:1.5em}
|
|
11
|
+
.markdown-body p,.markdown-body ul,.markdown-body ol,.markdown-body blockquote,.markdown-body table,.markdown-body pre{margin-top:0;margin-bottom:16px}
|
|
12
|
+
.markdown-body a{color:var(--fgColor-accent);text-decoration:none}
|
|
13
|
+
.markdown-body a:hover{text-decoration:underline}
|
|
14
|
+
.markdown-body code{padding:.2em .4em;border-radius:6px;background:var(--bgColor-neutral-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:85%}
|
|
15
|
+
.markdown-body pre{padding:16px;overflow:auto;border-radius:8px;background:var(--bgColor-muted)}
|
|
16
|
+
.markdown-body pre code{padding:0;background:transparent;font-size:100%}
|
|
17
|
+
.markdown-body table{display:block;width:max-content;max-width:100%;overflow:auto;border-spacing:0;border-collapse:collapse}
|
|
18
|
+
.markdown-body th,.markdown-body td{padding:6px 13px;border:1px solid var(--borderColor-default)}
|
|
19
|
+
.markdown-body tr{background:var(--bgColor-default);border-top:1px solid var(--borderColor-muted)}
|
|
20
|
+
.markdown-body tr:nth-child(2n){background:var(--bgColor-muted)}
|
|
21
|
+
.markdown-body blockquote{padding:0 1em;color:var(--fgColor-muted);border-left:.25em solid var(--borderColor-default)}
|
|
22
|
+
.file-viewer[data-viewer-theme='dark'] .markdown-viewer{background:#101820}
|
|
23
|
+
.file-viewer[data-viewer-theme='dark'] .markdown-body{color-scheme:dark;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;background:var(--bgColor-default);border-color:rgba(139,148,158,.26);color:var(--fgColor-default);box-shadow:0 24px 56px rgba(0,0,0,.38)}
|
|
24
|
+
@media (max-width:767px){.markdown-viewer{padding:14px 10px 28px}.markdown-body{padding:22px 18px;border-radius:10px}}
|
|
25
|
+
@media (prefers-color-scheme:dark){.file-viewer[data-viewer-theme='system'] .markdown-viewer{background:#101820}.file-viewer[data-viewer-theme='system'] .markdown-body{color-scheme:dark;--bgColor-default:#0d1117;--bgColor-muted:#151b23;--bgColor-neutral-muted:#656c7633;--borderColor-default:#3d444d;--borderColor-muted:#3d444db3;--borderColor-neutral-muted:#3d444db3;--fgColor-default:#f0f6fc;--fgColor-muted:#9198a1;--fgColor-accent:#4493f8;background:var(--bgColor-default);border-color:rgba(139,148,158,.26);color:var(--fgColor-default);box-shadow:0 24px 56px rgba(0,0,0,.38)}}
|
|
26
|
+
`;
|
|
27
|
+
const createStyle = () => {
|
|
28
|
+
const style = document.createElement('style');
|
|
29
|
+
style.textContent = markdownStyle;
|
|
30
|
+
return style;
|
|
31
|
+
};
|
|
32
|
+
const clampZoom = (value) => {
|
|
33
|
+
return Math.min(2.4, Math.max(0.6, Number(value.toFixed(2))));
|
|
34
|
+
};
|
|
35
|
+
const applyMarkdownZoom = (host, zoom) => {
|
|
36
|
+
host.style.setProperty('--markdown-max-width', `${980 * zoom}px`);
|
|
37
|
+
host.style.setProperty('--markdown-padding', `${45 * zoom}px`);
|
|
38
|
+
host.style.setProperty('--markdown-font-size', `${16 * zoom}px`);
|
|
39
|
+
};
|
|
40
|
+
export default async function renderMarkdown(buffer, target) {
|
|
41
|
+
const text = await readText(buffer);
|
|
42
|
+
let zoom = 1;
|
|
43
|
+
const zoomEmitter = createZoomChangeEmitter();
|
|
44
|
+
const root = document.createElement('div');
|
|
45
|
+
root.className = 'markdown-viewer';
|
|
46
|
+
root.dataset.viewerZoomProvider = 'markdown';
|
|
47
|
+
const article = document.createElement('article');
|
|
48
|
+
article.className = 'markdown-body';
|
|
49
|
+
article.innerHTML = await marked(text);
|
|
50
|
+
applyMarkdownZoom(root, zoom);
|
|
51
|
+
root.append(article);
|
|
52
|
+
target.replaceChildren(createStyle(), root);
|
|
53
|
+
const getZoomState = () => ({
|
|
54
|
+
scale: zoom,
|
|
55
|
+
label: `${Math.round(zoom * 100)}%`,
|
|
56
|
+
canZoomIn: zoom < 2.4,
|
|
57
|
+
canZoomOut: zoom > 0.6,
|
|
58
|
+
canReset: zoom !== 1,
|
|
59
|
+
minScale: 0.6,
|
|
60
|
+
maxScale: 2.4,
|
|
61
|
+
});
|
|
62
|
+
const setZoom = (scale) => {
|
|
63
|
+
zoom = clampZoom(scale);
|
|
64
|
+
applyMarkdownZoom(root, zoom);
|
|
65
|
+
zoomEmitter.emit();
|
|
66
|
+
return getZoomState();
|
|
67
|
+
};
|
|
68
|
+
registerFileViewerZoomProvider(root, {
|
|
69
|
+
zoomIn: () => setZoom(zoom + 0.1),
|
|
70
|
+
zoomOut: () => setZoom(zoom - 0.1),
|
|
71
|
+
resetZoom: () => setZoom(1),
|
|
72
|
+
setZoom,
|
|
73
|
+
getState: getZoomState,
|
|
74
|
+
subscribe: zoomEmitter.subscribe,
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
$el: target,
|
|
78
|
+
unmount() {
|
|
79
|
+
unregisterFileViewerZoomProvider(root);
|
|
80
|
+
target.replaceChildren();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|