@kandiforge/kandi-office 0.16.161 → 0.17.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.
Files changed (30) hide show
  1. package/dist/services/IDocumentService.d.ts +8 -1
  2. package/dist/services/TauriDocumentService.d.ts +5 -2
  3. package/dist/services/TauriDocumentService.js +46 -6
  4. package/dist/services/TauriDocumentService.js.map +1 -1
  5. package/dist/services/WasmDocumentService.d.ts +7 -2
  6. package/dist/services/WasmDocumentService.js +25 -3
  7. package/dist/services/WasmDocumentService.js.map +1 -1
  8. package/dist/viewers/DocxViewer.css +43 -46
  9. package/dist/viewers/DocxViewer.js +49 -100
  10. package/dist/viewers/DocxViewer.js.map +1 -1
  11. package/dist/viewers/XlsxViewer.css +9 -37
  12. package/dist/viewers/pdf/PdfViewer.js +17 -8
  13. package/dist/viewers/pdf/PdfViewer.js.map +1 -1
  14. package/dist/viewers/pdf/components/views/ContinuousScrollView.d.ts +1 -1
  15. package/dist/viewers/pdf/components/views/ContinuousScrollView.js +50 -36
  16. package/dist/viewers/pdf/components/views/ContinuousScrollView.js.map +1 -1
  17. package/dist/viewers/pdf/components/views/SinglePageView.d.ts +1 -1
  18. package/dist/viewers/pdf/components/views/SinglePageView.js +26 -16
  19. package/dist/viewers/pdf/components/views/SinglePageView.js.map +1 -1
  20. package/dist/viewers/pdf/components/views/ThumbnailGridView.js +23 -9
  21. package/dist/viewers/pdf/components/views/ThumbnailGridView.js.map +1 -1
  22. package/dist/viewers/pdf/hooks/usePdfDocument.d.ts +2 -0
  23. package/dist/viewers/pdf/hooks/usePdfDocument.js +84 -30
  24. package/dist/viewers/pdf/hooks/usePdfDocument.js.map +1 -1
  25. package/dist/viewers/pdf/types.d.ts +1 -0
  26. package/dist/wasm/types.d.ts +89 -0
  27. package/dist/wasm/xlsx.d.ts +8 -0
  28. package/dist/wasm/xlsx.js +34 -0
  29. package/dist/wasm/xlsx.js.map +1 -0
  30. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import type { LayoutPage, PptxExtractedData } from '../wasm/types';
1
+ import type { LayoutPage, PptxExtractedData, XlsxDocument, XlsxLayout } from '../wasm/types';
2
2
  export interface PptxDocumentHandle {
3
3
  slideCount: number;
4
4
  slideJsons: string[];
@@ -9,6 +9,10 @@ export interface DocxDocumentHandle {
9
9
  documentJson: string;
10
10
  pages: LayoutPage[];
11
11
  }
12
+ export interface XlsxDocumentHandle {
13
+ document: XlsxDocument;
14
+ layouts: XlsxLayout[];
15
+ }
12
16
  export interface PdfDocumentHandle {
13
17
  pageCount: number;
14
18
  path?: string;
@@ -28,6 +32,8 @@ export interface IDocumentService {
28
32
  openDocx(source: ArrayBuffer | string): Promise<DocxDocumentHandle>;
29
33
  getDocxPages(handle: DocxDocumentHandle): Promise<LayoutPage[]>;
30
34
  renderDocxPage(page: LayoutPage, canvas: HTMLCanvasElement): Promise<void>;
35
+ openXlsx(source: ArrayBuffer | string): Promise<XlsxDocumentHandle>;
36
+ renderXlsxSheet(layout: XlsxLayout, canvas: HTMLCanvasElement): Promise<void>;
31
37
  openPdf(source: ArrayBuffer | string): Promise<PdfDocumentHandle>;
32
38
  getPdfPageCount(handle: PdfDocumentHandle): number;
33
39
  getPdfPageDimensions(handle: PdfDocumentHandle, page: number): Promise<{
@@ -35,6 +41,7 @@ export interface IDocumentService {
35
41
  height: number;
36
42
  }>;
37
43
  renderPdfPage(handle: PdfDocumentHandle, page: number, canvas: HTMLCanvasElement, dpi?: number): Promise<string>;
44
+ renderPdfPageToCanvas(handle: PdfDocumentHandle, page: number, canvas: HTMLCanvasElement, dpi?: number): Promise<void>;
38
45
  closePdf(handle: PdfDocumentHandle): Promise<void>;
39
46
  openMarkdown(source: ArrayBuffer | string): Promise<{
40
47
  content: string;
@@ -1,5 +1,5 @@
1
- import type { IDocumentService, PptxDocumentHandle, DocxDocumentHandle, PdfDocumentHandle, SlideInfo } from './IDocumentService';
2
- import type { LayoutPage } from '../wasm/types';
1
+ import type { IDocumentService, PptxDocumentHandle, DocxDocumentHandle, XlsxDocumentHandle, PdfDocumentHandle, SlideInfo } from './IDocumentService';
2
+ import type { LayoutPage, XlsxLayout } from '../wasm/types';
3
3
  export declare class TauriDocumentService implements IDocumentService {
4
4
  openPptx(source: ArrayBuffer | string): Promise<PptxDocumentHandle>;
5
5
  getSlides(handle: PptxDocumentHandle): Promise<SlideInfo[]>;
@@ -8,12 +8,15 @@ export declare class TauriDocumentService implements IDocumentService {
8
8
  openDocx(source: ArrayBuffer | string): Promise<DocxDocumentHandle>;
9
9
  getDocxPages(handle: DocxDocumentHandle): Promise<LayoutPage[]>;
10
10
  renderDocxPage(page: LayoutPage, canvas: HTMLCanvasElement): Promise<void>;
11
+ openXlsx(source: ArrayBuffer | string): Promise<XlsxDocumentHandle>;
12
+ renderXlsxSheet(layout: XlsxLayout, canvas: HTMLCanvasElement): Promise<void>;
11
13
  openPdf(source: ArrayBuffer | string): Promise<PdfDocumentHandle>;
12
14
  getPdfPageCount(handle: PdfDocumentHandle): number;
13
15
  getPdfPageDimensions(handle: PdfDocumentHandle, pageNum: number): Promise<{
14
16
  width: number;
15
17
  height: number;
16
18
  }>;
19
+ renderPdfPageToCanvas(handle: PdfDocumentHandle, pageNum: number, canvas: HTMLCanvasElement, dpi?: number): Promise<void>;
17
20
  renderPdfPage(_handle: PdfDocumentHandle, pageNum: number, _canvas: HTMLCanvasElement, dpi?: number): Promise<string>;
18
21
  closePdf(_handle: PdfDocumentHandle): Promise<void>;
19
22
  openMarkdown(source: ArrayBuffer | string): Promise<{
@@ -41,12 +41,14 @@ export class TauriDocumentService {
41
41
  throw new Error('TauriDocumentService requires a file path string for DOCX, not ArrayBuffer');
42
42
  }
43
43
  const invoke = await getInvoke();
44
- await invoke('open_document', { path: source });
45
- const structure = await invoke('docx_get_structure');
46
- return {
47
- documentJson: JSON.stringify(structure),
48
- pages: [],
49
- };
44
+ const bytes = await invoke('read_file_bytes', { path: source });
45
+ const buffer = new Uint8Array(bytes).buffer;
46
+ const { initWasm } = await import('../wasm/wasm-loader');
47
+ const { processDocx } = await import('../wasm/docx');
48
+ await initWasm();
49
+ const measureCanvas = document.createElement('canvas');
50
+ const { documentJson, pages } = await processDocx(buffer, measureCanvas);
51
+ return { documentJson, pages };
50
52
  }
51
53
  async getDocxPages(handle) {
52
54
  return handle.pages;
@@ -57,6 +59,25 @@ export class TauriDocumentService {
57
59
  await init();
58
60
  await wasmRender(page, canvas);
59
61
  }
62
+ async openXlsx(source) {
63
+ if (typeof source !== 'string') {
64
+ throw new Error('TauriDocumentService requires a file path string for XLSX, not ArrayBuffer');
65
+ }
66
+ const invoke = await getInvoke();
67
+ const bytes = await invoke('read_file_bytes', { path: source });
68
+ const buffer = new Uint8Array(bytes).buffer;
69
+ const { initWasm } = await import('../wasm/wasm-loader');
70
+ const { processXlsx } = await import('../wasm/xlsx');
71
+ await initWasm();
72
+ const { document, layouts } = await processXlsx(buffer);
73
+ return { document, layouts };
74
+ }
75
+ async renderXlsxSheet(layout, canvas) {
76
+ const { initWasm } = await import('../wasm/wasm-loader');
77
+ const { renderXlsxSheet: wasmRender } = await import('../wasm/xlsx');
78
+ await initWasm();
79
+ await wasmRender(layout, canvas);
80
+ }
60
81
  async openPdf(source) {
61
82
  if (typeof source !== 'string') {
62
83
  throw new Error('TauriDocumentService requires a file path string for PDF, not ArrayBuffer');
@@ -78,6 +99,25 @@ export class TauriDocumentService {
78
99
  });
79
100
  return { width, height };
80
101
  }
102
+ async renderPdfPageToCanvas(handle, pageNum, canvas, dpi = 150) {
103
+ const dataUri = await this.renderPdfPage(handle, pageNum, canvas, dpi);
104
+ const img = new Image();
105
+ await new Promise((resolve, reject) => {
106
+ img.onload = () => {
107
+ canvas.width = img.naturalWidth;
108
+ canvas.height = img.naturalHeight;
109
+ const ctx = canvas.getContext('2d');
110
+ if (!ctx) {
111
+ reject(new Error('Failed to get canvas 2d context'));
112
+ return;
113
+ }
114
+ ctx.drawImage(img, 0, 0);
115
+ resolve();
116
+ };
117
+ img.onerror = () => reject(new Error('Failed to load rendered page image'));
118
+ img.src = dataUri;
119
+ });
120
+ }
81
121
  async renderPdfPage(_handle, pageNum, _canvas, dpi = 150) {
82
122
  const invoke = await getInvoke();
83
123
  return invoke('pdf_render_page_to_image', {
@@ -1 +1 @@
1
- {"version":3,"file":"TauriDocumentService.js","sourceRoot":"","sources":["../../src/services/TauriDocumentService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TauriDocumentService.js","sourceRoot":"","sources":["../../src/services/TauriDocumentService.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { IDocumentService, PptxDocumentHandle, DocxDocumentHandle, PdfDocumentHandle, SlideInfo } from './IDocumentService';
2
- import type { LayoutPage } from '../wasm/types';
1
+ import type { IDocumentService, PptxDocumentHandle, DocxDocumentHandle, XlsxDocumentHandle, PdfDocumentHandle, SlideInfo } from './IDocumentService';
2
+ import type { LayoutPage, XlsxLayout } from '../wasm/types';
3
3
  export declare class WasmDocumentService implements IDocumentService {
4
4
  openPptx(source: ArrayBuffer | string): Promise<PptxDocumentHandle>;
5
5
  getSlides(handle: PptxDocumentHandle): Promise<SlideInfo[]>;
@@ -8,12 +8,17 @@ export declare class WasmDocumentService implements IDocumentService {
8
8
  openDocx(source: ArrayBuffer | string): Promise<DocxDocumentHandle>;
9
9
  getDocxPages(handle: DocxDocumentHandle): Promise<LayoutPage[]>;
10
10
  renderDocxPage(page: LayoutPage, canvas: HTMLCanvasElement): Promise<void>;
11
+ openXlsx(source: ArrayBuffer | string): Promise<XlsxDocumentHandle>;
12
+ renderXlsxSheet(layout: XlsxLayout, canvas: HTMLCanvasElement): Promise<void>;
11
13
  openPdf(source: ArrayBuffer | string): Promise<PdfDocumentHandle>;
12
14
  getPdfPageCount(handle: PdfDocumentHandle): number;
13
15
  getPdfPageDimensions(handle: PdfDocumentHandle, pageNum: number): Promise<{
14
16
  width: number;
15
17
  height: number;
16
18
  }>;
19
+ private _getPdfPage;
20
+ private _renderToCanvas;
21
+ renderPdfPageToCanvas(handle: PdfDocumentHandle, pageNum: number, canvas: HTMLCanvasElement, dpi?: number): Promise<void>;
17
22
  renderPdfPage(handle: PdfDocumentHandle, pageNum: number, canvas: HTMLCanvasElement, dpi?: number): Promise<string>;
18
23
  closePdf(handle: PdfDocumentHandle): Promise<void>;
19
24
  openMarkdown(source: ArrayBuffer | string): Promise<{
@@ -1,5 +1,6 @@
1
1
  import { extractPptx, parsePptxSlides, renderSlideToCanvas } from '../wasm/pptx';
2
2
  import { processDocx, renderDocxPage as wasmRenderDocxPage } from '../wasm/docx';
3
+ import { processXlsx, renderXlsxSheet as wasmRenderXlsxSheet } from '../wasm/xlsx';
3
4
  import { initWasm } from '../wasm/wasm-loader';
4
5
  export class WasmDocumentService {
5
6
  async openPptx(source) {
@@ -53,6 +54,18 @@ export class WasmDocumentService {
53
54
  await initWasm();
54
55
  await wasmRenderDocxPage(page, canvas);
55
56
  }
57
+ async openXlsx(source) {
58
+ if (typeof source === 'string') {
59
+ throw new Error('WasmDocumentService requires ArrayBuffer for XLSX, not a file path');
60
+ }
61
+ await initWasm();
62
+ const { document, layouts } = await processXlsx(source);
63
+ return { document, layouts };
64
+ }
65
+ async renderXlsxSheet(layout, canvas) {
66
+ await initWasm();
67
+ await wasmRenderXlsxSheet(layout, canvas);
68
+ }
56
69
  async openPdf(source) {
57
70
  if (typeof source === 'string') {
58
71
  throw new Error('WasmDocumentService requires ArrayBuffer for PDF, not a file path');
@@ -76,9 +89,12 @@ export class WasmDocumentService {
76
89
  const viewport = page.getViewport({ scale: 1 });
77
90
  return { width: viewport.width, height: viewport.height };
78
91
  }
79
- async renderPdfPage(handle, pageNum, canvas, dpi = 150) {
92
+ async _getPdfPage(handle, pageNum) {
80
93
  const doc = handle.doc;
81
- const page = await doc.getPage(pageNum + 1);
94
+ return doc.getPage(pageNum + 1);
95
+ }
96
+ async _renderToCanvas(handle, pageNum, canvas, dpi) {
97
+ const page = await this._getPdfPage(handle, pageNum);
82
98
  const scale = dpi / 72;
83
99
  const viewport = page.getViewport({ scale });
84
100
  canvas.width = viewport.width;
@@ -87,7 +103,13 @@ export class WasmDocumentService {
87
103
  if (!ctx)
88
104
  throw new Error('Failed to get canvas 2d context');
89
105
  await page.render({ canvasContext: ctx, viewport }).promise;
90
- return canvas.toDataURL('image/png');
106
+ }
107
+ async renderPdfPageToCanvas(handle, pageNum, canvas, dpi = 150) {
108
+ await this._renderToCanvas(handle, pageNum, canvas, dpi);
109
+ }
110
+ async renderPdfPage(handle, pageNum, canvas, dpi = 150) {
111
+ await this._renderToCanvas(handle, pageNum, canvas, dpi);
112
+ return canvas.toDataURL('image/jpeg', 0.85);
91
113
  }
92
114
  async closePdf(handle) {
93
115
  const doc = handle.doc;
@@ -1 +1 @@
1
- {"version":3,"file":"WasmDocumentService.js","sourceRoot":"","sources":["../../src/services/WasmDocumentService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WasmDocumentService.js","sourceRoot":"","sources":["../../src/services/WasmDocumentService.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,8 @@
5
5
  background: var(--document-bg);
6
6
  }
7
7
 
8
+ /* ── Filmstrip sidebar ── */
9
+
8
10
  .docx-filmstrip {
9
11
  width: 200px;
10
12
  background: var(--surface);
@@ -13,10 +15,40 @@
13
15
  flex-direction: column;
14
16
  overflow-y: auto;
15
17
  flex-shrink: 0;
18
+ transition: width 0.2s ease;
19
+ }
20
+
21
+ .docx-filmstrip.collapsed {
22
+ width: 36px;
23
+ overflow: hidden;
16
24
  }
17
25
 
18
- .docx-filmstrip h3 {
19
- margin: 12px;
26
+ .docx-filmstrip-header {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: 8px;
30
+ padding: 8px 12px;
31
+ }
32
+
33
+ .docx-filmstrip-toggle {
34
+ background: none;
35
+ border: 1px solid var(--border-default);
36
+ border-radius: 4px;
37
+ color: var(--text-secondary);
38
+ cursor: pointer;
39
+ padding: 2px 6px;
40
+ font-size: 11px;
41
+ line-height: 1;
42
+ transition: background 0.15s, color 0.15s;
43
+ }
44
+
45
+ .docx-filmstrip-toggle:hover {
46
+ background: var(--surface-elevated);
47
+ color: var(--text-primary);
48
+ }
49
+
50
+ .docx-filmstrip-header h3 {
51
+ margin: 0;
20
52
  font-size: 14px;
21
53
  font-weight: 600;
22
54
  color: var(--text-secondary);
@@ -80,6 +112,8 @@
80
112
  color: var(--text-muted);
81
113
  }
82
114
 
115
+ /* ── Main viewer ── */
116
+
83
117
  .docx-viewer-main {
84
118
  flex: 1;
85
119
  display: flex;
@@ -96,6 +130,11 @@
96
130
  gap: 20px;
97
131
  }
98
132
 
133
+ .docx-page-canvas {
134
+ background: var(--document-surface);
135
+ box-shadow: var(--shadow-md, 0 2px 8px rgba(0, 0, 0, 0.3));
136
+ }
137
+
99
138
  .docx-page-controls {
100
139
  display: flex;
101
140
  gap: 16px;
@@ -127,6 +166,8 @@
127
166
  opacity: 0.5;
128
167
  }
129
168
 
169
+ /* ── Loading / error / empty states ── */
170
+
130
171
  .docx-viewer {
131
172
  width: 100%;
132
173
  height: 100%;
@@ -160,50 +201,6 @@
160
201
  margin-top: 0;
161
202
  }
162
203
 
163
- .docx-page {
164
- background: var(--document-surface);
165
- box-shadow: var(--shadow-md, 0 2px 8px rgba(0, 0, 0, 0.3));
166
- margin-bottom: 20px;
167
- font-family: 'Calibri', 'Arial', sans-serif;
168
- font-size: 11pt;
169
- line-height: 1.15;
170
- color: var(--document-text, #000);
171
- }
172
-
173
- .docx-paragraph {
174
- margin-bottom: 8pt;
175
- white-space: pre-wrap;
176
- word-wrap: break-word;
177
- }
178
-
179
- .docx-paragraph:empty {
180
- min-height: 1em;
181
- }
182
-
183
- .docx-table {
184
- width: 100%;
185
- border-collapse: collapse;
186
- margin: 12pt 0;
187
- }
188
-
189
- .docx-table td {
190
- border: 1px solid var(--border-default);
191
- padding: 4pt 8pt;
192
- vertical-align: top;
193
- }
194
-
195
- .docx-info {
196
- color: var(--text-primary);
197
- font-size: 12px;
198
- padding: 10px;
199
- background: var(--surface-elevated);
200
- border-radius: 4px;
201
- }
202
-
203
- .docx-info span + span {
204
- margin-left: 8px;
205
- }
206
-
207
204
  .empty-state {
208
205
  color: var(--text-primary);
209
206
  font-size: 16px;
@@ -1,18 +1,16 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState, useRef } from 'react';
2
+ import { useEffect, useState, useRef, useCallback } from 'react';
3
3
  import { getDocumentService } from '../services/documentServiceRegistry';
4
4
 
5
5
  export function DocxViewer({ fileData, filePath } = {}) {
6
- const [paragraphs, setParagraphs] = useState([]);
7
- const [tables, setTables] = useState([]);
8
- const [structure, setStructure] = useState(null);
9
6
  const [pages, setPages] = useState([]);
10
7
  const [currentPage, setCurrentPage] = useState(0);
11
8
  const [loading, setLoading] = useState(true);
12
9
  const [error, setError] = useState(null);
13
10
  const [thumbnails, setThumbnails] = useState(new Map());
14
- const [docHandle, setDocHandle] = useState(null);
15
- const pageRefs = useRef(new Map());
11
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
12
+ const canvasRef = useRef(null);
13
+ const docHandleRef = useRef(null);
16
14
  useEffect(() => {
17
15
  const loadDocument = async () => {
18
16
  try {
@@ -20,43 +18,13 @@ export function DocxViewer({ fileData, filePath } = {}) {
20
18
  const service = getDocumentService();
21
19
  if (fileData) {
22
20
  const handle = await service.openDocx(fileData);
23
- setDocHandle(handle);
24
- const parsed = JSON.parse(handle.documentJson);
25
- setStructure({
26
- paragraph_count: parsed.paragraphs?.length ?? 0,
27
- table_count: parsed.tables?.length ?? 0,
28
- page_width: parsed.page_width ?? 612,
29
- page_height: parsed.page_height ?? 792,
30
- margins: parsed.margins ?? { top: 72, bottom: 72, left: 72, right: 72 },
31
- });
32
- const wasmParas = (parsed.paragraphs ?? []).map((p, i) => ({
33
- index: i,
34
- text: p.runs?.map((r) => r.text).join('') ?? '',
35
- runs: (p.runs ?? []).map((r) => ({
36
- text: r.text,
37
- style: {
38
- bold: r.bold ?? false,
39
- italic: r.italic ?? false,
40
- underline: r.underline ?? false,
41
- font_family: r.font_family,
42
- font_size: r.font_size,
43
- color: r.color,
44
- },
45
- })),
46
- has_style: false,
47
- has_numbering: false,
48
- }));
49
- setParagraphs(wasmParas);
50
- setTables([]);
21
+ docHandleRef.current = handle;
22
+ setPages(handle.pages);
51
23
  }
52
- else {
53
- const invoke = (await new Function('m', 'return import(m)')('@tauri-apps/api/core')).invoke;
54
- const structureData = await invoke('docx_get_structure', {});
55
- setStructure(structureData);
56
- const paraData = await invoke('docx_get_paragraphs', {});
57
- setParagraphs(paraData.paragraphs);
58
- const tableData = await invoke('docx_get_tables', {});
59
- setTables(tableData.tables);
24
+ else if (filePath) {
25
+ const handle = await service.openDocx(filePath);
26
+ docHandleRef.current = handle;
27
+ setPages(handle.pages);
60
28
  }
61
29
  setLoading(false);
62
30
  }
@@ -68,53 +36,57 @@ export function DocxViewer({ fileData, filePath } = {}) {
68
36
  };
69
37
  loadDocument();
70
38
  }, [fileData, filePath]);
71
- useEffect(() => {
72
- if (!structure || paragraphs.length === 0)
39
+ const renderCurrentPage = useCallback(async () => {
40
+ if (!canvasRef.current || pages.length === 0)
41
+ return;
42
+ const page = pages[currentPage];
43
+ if (!page)
73
44
  return;
74
- const PARAGRAPHS_PER_PAGE = 30;
75
- const newPages = [];
76
- for (let i = 0; i < paragraphs.length; i += PARAGRAPHS_PER_PAGE) {
77
- newPages.push({
78
- paragraphs: paragraphs.slice(i, i + PARAGRAPHS_PER_PAGE),
79
- tables: []
80
- });
45
+ const canvas = canvasRef.current;
46
+ canvas.width = page.width;
47
+ canvas.height = page.height;
48
+ try {
49
+ const service = getDocumentService();
50
+ await service.renderDocxPage(page, canvas);
81
51
  }
82
- if (newPages.length > 0 && tables.length > 0) {
83
- newPages[0].tables = tables;
52
+ catch (err) {
53
+ console.error('Failed to render DOCX page:', err);
84
54
  }
85
- setPages(newPages);
86
- }, [paragraphs, tables, structure]);
55
+ }, [pages, currentPage]);
56
+ useEffect(() => {
57
+ renderCurrentPage();
58
+ }, [renderCurrentPage]);
87
59
  useEffect(() => {
88
60
  if (pages.length === 0)
89
61
  return;
90
62
  const generateThumbnails = async () => {
63
+ const service = getDocumentService();
91
64
  for (let i = 0; i < pages.length; i++) {
92
- const pageElement = pageRefs.current.get(i);
93
- if (!pageElement)
94
- continue;
95
65
  try {
96
- const canvas = document.createElement('canvas');
97
- canvas.width = 200;
98
- canvas.height = 283;
99
- const ctx = canvas.getContext('2d');
66
+ const page = pages[i];
67
+ const aspectRatio = page.width / page.height;
68
+ const thumbWidth = 200;
69
+ const thumbHeight = Math.round(thumbWidth / aspectRatio);
70
+ const fullCanvas = document.createElement('canvas');
71
+ fullCanvas.width = page.width;
72
+ fullCanvas.height = page.height;
73
+ await service.renderDocxPage(page, fullCanvas);
74
+ const thumbCanvas = document.createElement('canvas');
75
+ thumbCanvas.width = thumbWidth;
76
+ thumbCanvas.height = thumbHeight;
77
+ const ctx = thumbCanvas.getContext('2d');
100
78
  if (!ctx)
101
79
  continue;
102
- ctx.fillStyle = 'white';
103
- ctx.fillRect(0, 0, canvas.width, canvas.height);
104
- ctx.fillStyle = '#333';
105
- ctx.font = '48px Arial';
106
- ctx.textAlign = 'center';
107
- ctx.textBaseline = 'middle';
108
- ctx.fillText(`${i + 1}`, canvas.width / 2, canvas.height / 2);
109
- const dataUrl = canvas.toDataURL();
80
+ ctx.drawImage(fullCanvas, 0, 0, thumbWidth, thumbHeight);
81
+ const dataUrl = thumbCanvas.toDataURL('image/png');
110
82
  setThumbnails(prev => new Map(prev).set(i, dataUrl));
111
83
  }
112
84
  catch (err) {
113
- console.error('Failed to generate thumbnail:', err);
85
+ console.error(`Failed to generate thumbnail for page ${i}:`, err);
114
86
  }
115
87
  }
116
88
  };
117
- setTimeout(generateThumbnails, 100);
89
+ generateThumbnails();
118
90
  }, [pages]);
119
91
  if (loading) {
120
92
  return (_jsx("div", { className: "docx-viewer loading", children: _jsx("div", { className: "loading-spinner", children: "Loading document..." }) }));
@@ -125,33 +97,10 @@ export function DocxViewer({ fileData, filePath } = {}) {
125
97
  if (pages.length === 0) {
126
98
  return (_jsx("div", { className: "docx-viewer", children: _jsx("div", { className: "empty-state", children: "No content to display" }) }));
127
99
  }
128
- const currentPageContent = pages[currentPage];
129
- return (_jsxs("div", { className: "docx-viewer-container", children: [_jsxs("aside", { className: "docx-filmstrip", children: [_jsx("h3", { children: "Pages" }), _jsx("div", { className: "docx-thumbnail-list", children: pages.map((_, pageIdx) => (_jsxs("div", { className: `docx-thumbnail ${currentPage === pageIdx ? 'active' : ''}`, onClick: () => setCurrentPage(pageIdx), children: [_jsx("div", { className: "docx-thumbnail-number", children: pageIdx + 1 }), thumbnails.has(pageIdx) ? (_jsx("img", { src: thumbnails.get(pageIdx), alt: `Page ${pageIdx + 1}` })) : (_jsx("div", { className: "docx-thumbnail-loading", children: "Loading..." }))] }, pageIdx))) })] }), _jsx("main", { className: "docx-viewer-main", children: _jsxs("div", { className: "docx-page-container", children: [_jsxs("div", { className: "docx-page", ref: (el) => {
130
- if (el)
131
- pageRefs.current.set(currentPage, el);
132
- }, style: {
133
- width: structure ? `${structure.page_width}px` : '612px',
134
- minHeight: structure ? `${structure.page_height}px` : '792px',
135
- padding: structure
136
- ? `${structure.margins.top}px ${structure.margins.right}px ${structure.margins.bottom}px ${structure.margins.left}px`
137
- : '72px'
138
- }, children: [currentPageContent.paragraphs.map((para) => (_jsx("div", { className: "docx-paragraph", children: para.runs.map((run, runIdx) => {
139
- const style = {
140
- fontWeight: run.style.bold ? 'bold' : 'normal',
141
- fontStyle: run.style.italic ? 'italic' : 'normal',
142
- textDecoration: run.style.underline ? 'underline' : 'none',
143
- };
144
- if (run.style.font_family) {
145
- style.fontFamily = run.style.font_family;
146
- }
147
- if (run.style.font_size) {
148
- style.fontSize = `${run.style.font_size}pt`;
149
- }
150
- if (run.style.color) {
151
- const c = run.style.color;
152
- style.color = `rgba(${c.r}, ${c.g}, ${c.b}, ${c.a ?? 1})`;
153
- }
154
- return (_jsx("span", { style: style, children: run.text }, runIdx));
155
- }) }, para.index))), currentPageContent.tables.map((table) => (_jsx("table", { className: "docx-table", children: _jsx("tbody", { children: table.rows.map((row) => (_jsx("tr", { children: row.cells.map((cell) => (_jsx("td", { children: cell.text }, cell.cell_index))) }, row.row_index))) }) }, table.table_index)))] }), _jsxs("div", { className: "docx-page-controls", children: [_jsx("button", { onClick: () => setCurrentPage(Math.max(0, currentPage - 1)), disabled: currentPage === 0, children: "\u2190 Previous" }), _jsxs("span", { children: ["Page ", currentPage + 1, " of ", pages.length] }), _jsx("button", { onClick: () => setCurrentPage(Math.min(pages.length - 1, currentPage + 1)), disabled: currentPage === pages.length - 1, children: "Next \u2192" })] })] }) })] }));
100
+ const page = pages[currentPage];
101
+ return (_jsxs("div", { className: "docx-viewer-container", children: [_jsxs("aside", { className: `docx-filmstrip ${sidebarCollapsed ? 'collapsed' : ''}`, children: [_jsxs("div", { className: "docx-filmstrip-header", children: [_jsx("button", { className: "docx-filmstrip-toggle", onClick: () => setSidebarCollapsed(!sidebarCollapsed), title: sidebarCollapsed ? 'Show pages' : 'Hide pages', children: sidebarCollapsed ? '\u25B6' : '\u25C0' }), !sidebarCollapsed && _jsx("h3", { children: "Pages" })] }), !sidebarCollapsed && (_jsx("div", { className: "docx-thumbnail-list", children: pages.map((_, pageIdx) => (_jsxs("div", { className: `docx-thumbnail ${currentPage === pageIdx ? 'active' : ''}`, onClick: () => setCurrentPage(pageIdx), children: [_jsx("div", { className: "docx-thumbnail-number", children: pageIdx + 1 }), thumbnails.has(pageIdx) ? (_jsx("img", { src: thumbnails.get(pageIdx), alt: `Page ${pageIdx + 1}` })) : (_jsx("div", { className: "docx-thumbnail-loading", children: "Loading..." }))] }, pageIdx))) }))] }), _jsx("main", { className: "docx-viewer-main", children: _jsxs("div", { className: "docx-page-container", children: [_jsx("canvas", { ref: canvasRef, className: "docx-page-canvas", style: {
102
+ width: `${page.width}px`,
103
+ height: `${page.height}px`,
104
+ } }), _jsxs("div", { className: "docx-page-controls", children: [_jsx("button", { onClick: () => setCurrentPage(Math.max(0, currentPage - 1)), disabled: currentPage === 0, children: "\u2190 Previous" }), _jsxs("span", { children: ["Page ", currentPage + 1, " of ", pages.length] }), _jsx("button", { onClick: () => setCurrentPage(Math.min(pages.length - 1, currentPage + 1)), disabled: currentPage === pages.length - 1, children: "Next \u2192" })] })] }) })] }));
156
105
  }
157
106
  //# sourceMappingURL=DocxViewer.js.map