@tfw.in/structura-lib 0.2.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/PRODUCTION_ARCHITECTURE.md +511 -0
- package/README.md +379 -0
- package/SAVE_FUNCTIONALITY_COMPLETE.md +448 -0
- package/dist/cjs/EditableContent.js +150 -0
- package/dist/cjs/HtmlViewer.js +587 -0
- package/dist/cjs/PdfComponents.js +16 -0
- package/dist/cjs/PdfDocumentViewer.js +281 -0
- package/dist/cjs/Structura.js +806 -0
- package/dist/cjs/Table.js +164 -0
- package/dist/cjs/TableCell.js +115 -0
- package/dist/cjs/accuracyMetrics.js +39 -0
- package/dist/cjs/helpers/preprocessData.js +143 -0
- package/dist/cjs/index.js +7 -0
- package/dist/cjs/lib/polyfills.js +15 -0
- package/dist/cjs/lib/utils.js +10 -0
- package/dist/cjs/node_modules/react-icons/fa/index.esm.js +14 -0
- package/dist/cjs/node_modules/react-icons/lib/esm/iconBase.js +69 -0
- package/dist/cjs/node_modules/react-icons/lib/esm/iconContext.js +15 -0
- package/dist/cjs/polyfills.js +19 -0
- package/dist/cjs/route.js +102 -0
- package/dist/cjs/styles.css +7 -0
- package/dist/cjs/styles.css.map +1 -0
- package/dist/cjs/ui/badge.js +34 -0
- package/dist/cjs/ui/button.js +71 -0
- package/dist/cjs/ui/card.js +86 -0
- package/dist/cjs/ui/progress.js +45 -0
- package/dist/cjs/ui/scroll-area.js +62 -0
- package/dist/cjs/ui/tabs.js +60 -0
- package/dist/cjs/worker.js +36 -0
- package/dist/esm/EditableContent.js +161 -0
- package/dist/esm/HtmlViewer.js +640 -0
- package/dist/esm/PdfComponents.js +21 -0
- package/dist/esm/PdfDocumentViewer.js +294 -0
- package/dist/esm/Structura.js +951 -0
- package/dist/esm/Table.js +182 -0
- package/dist/esm/TableCell.js +122 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +305 -0
- package/dist/esm/accuracyMetrics.js +41 -0
- package/dist/esm/helpers/preprocessData.js +152 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/lib/polyfills.js +13 -0
- package/dist/esm/lib/utils.js +8 -0
- package/dist/esm/node_modules/react-icons/fa/index.esm.js +11 -0
- package/dist/esm/node_modules/react-icons/lib/esm/iconBase.js +66 -0
- package/dist/esm/node_modules/react-icons/lib/esm/iconContext.js +12 -0
- package/dist/esm/polyfills.js +17 -0
- package/dist/esm/route.js +154 -0
- package/dist/esm/styles.css +7 -0
- package/dist/esm/styles.css.map +1 -0
- package/dist/esm/types/EditableContent.d.ts +9 -0
- package/dist/esm/types/HtmlViewer.d.ts +10 -0
- package/dist/esm/types/PdfComponents.d.ts +35 -0
- package/dist/esm/types/PdfDocumentViewer.d.ts +22 -0
- package/dist/esm/types/Structura.d.ts +11 -0
- package/dist/esm/types/Table.d.ts +12 -0
- package/dist/esm/types/TableCell.d.ts +13 -0
- package/dist/esm/types/accuracy.d.ts +23 -0
- package/dist/esm/types/accuracyMetrics.d.ts +5 -0
- package/dist/esm/types/helpers/flattenJSON.d.ts +1 -0
- package/dist/esm/types/helpers/hardMerging.d.ts +2 -0
- package/dist/esm/types/helpers/index.d.ts +6 -0
- package/dist/esm/types/helpers/jsonToHtml.d.ts +40 -0
- package/dist/esm/types/helpers/preprocessData.d.ts +3 -0
- package/dist/esm/types/helpers/removeMetadata.d.ts +1 -0
- package/dist/esm/types/helpers/tableProcessor.d.ts +1 -0
- package/dist/esm/types/index.d.ts +3 -0
- package/dist/esm/types/lib/polyfills.d.ts +1 -0
- package/dist/esm/types/lib/utils.d.ts +2 -0
- package/dist/esm/types/polyfills.d.ts +1 -0
- package/dist/esm/types/route.d.ts +45 -0
- package/dist/esm/types/test-app/src/App.d.ts +4 -0
- package/dist/esm/types/test-app/src/main.d.ts +1 -0
- package/dist/esm/types/test-app/vite.config.d.ts +2 -0
- package/dist/esm/types/types.d.ts +23 -0
- package/dist/esm/types/ui/alert.d.ts +8 -0
- package/dist/esm/types/ui/badge.d.ts +9 -0
- package/dist/esm/types/ui/button.d.ts +11 -0
- package/dist/esm/types/ui/card.d.ts +8 -0
- package/dist/esm/types/ui/progress.d.ts +6 -0
- package/dist/esm/types/ui/scroll-area.d.ts +5 -0
- package/dist/esm/types/ui/skeleton.d.ts +2 -0
- package/dist/esm/types/ui/tabs.d.ts +7 -0
- package/dist/esm/types/worker.d.ts +1 -0
- package/dist/esm/ui/badge.js +31 -0
- package/dist/esm/ui/button.js +50 -0
- package/dist/esm/ui/card.js +67 -0
- package/dist/esm/ui/progress.js +26 -0
- package/dist/esm/ui/scroll-area.js +45 -0
- package/dist/esm/ui/tabs.js +39 -0
- package/dist/esm/worker.js +50 -0
- package/dist/index.d.ts +38 -0
- package/package.json +85 -0
- package/server/README.md +203 -0
- package/server/db.js +142 -0
- package/server/server.js +165 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
require('./polyfills.js');
|
|
8
|
+
var PdfComponents = require('./PdfComponents.js');
|
|
9
|
+
require('./worker.js');
|
|
10
|
+
|
|
11
|
+
function PdfDocumentViewer({
|
|
12
|
+
fileUrl,
|
|
13
|
+
allowedPages,
|
|
14
|
+
onLoadSuccess,
|
|
15
|
+
onFileUpload,
|
|
16
|
+
onRemovePDF,
|
|
17
|
+
jsonData,
|
|
18
|
+
selectedBboxId,
|
|
19
|
+
onPdfBboxClick // Destructure new prop
|
|
20
|
+
}) {
|
|
21
|
+
// console.log("[PdfDocumentViewer] Props received:", { fileUrl: !!fileUrl, jsonData: !!jsonData, selectedBboxId, onPdfBboxClick: !!onPdfBboxClick, allowedPages });
|
|
22
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
23
|
+
const [pageScales, setPageScales] = React.useState({}); // To store scale for each page
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
// console.log("[PdfDocumentViewer] pageScales updated:", pageScales);
|
|
26
|
+
}, [pageScales]);
|
|
27
|
+
const handleDragOver = React.useCallback(e => {
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
setIsDragging(true);
|
|
30
|
+
}, []);
|
|
31
|
+
React.useCallback(e => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
setIsDragging(false);
|
|
34
|
+
}, []);
|
|
35
|
+
const handleDrop = React.useCallback(e => {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
setIsDragging(false);
|
|
38
|
+
// console.log('!!! [PdfDocumentViewer] Drop event triggered');
|
|
39
|
+
// First check if we have drag data (from FileTree)
|
|
40
|
+
e.dataTransfer.getData('text/plain');
|
|
41
|
+
// console.log('!!! [PdfDocumentViewer] Available data types:', e.dataTransfer.types);
|
|
42
|
+
// Handle direct file drops (from computer)
|
|
43
|
+
const files = e.dataTransfer.files;
|
|
44
|
+
if (files.length > 0) {
|
|
45
|
+
const file = files[0];
|
|
46
|
+
// console.log('!!! [PdfDocumentViewer] File dropped:', file.name, file.type);
|
|
47
|
+
if (file.type === "application/pdf") {
|
|
48
|
+
// console.log('!!! [PdfDocumentViewer] Valid PDF file, calling onFileUpload');
|
|
49
|
+
onFileUpload(file);
|
|
50
|
+
} else {
|
|
51
|
+
// console.log('!!! [PdfDocumentViewer] Invalid file type:', file.type);
|
|
52
|
+
alert("Please upload a PDF file");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}, [onFileUpload]);
|
|
56
|
+
const renderUploadArea = () => jsxRuntime.jsxs("div", {
|
|
57
|
+
className: `structura-upload-container ${isDragging ? 'border-blue-500 bg-blue-50' : ''}`,
|
|
58
|
+
onDragOver: handleDragOver,
|
|
59
|
+
onDragEnter: () => setIsDragging(true),
|
|
60
|
+
onDragLeave: () => setIsDragging(false),
|
|
61
|
+
onDrop: handleDrop,
|
|
62
|
+
onClick: () => {
|
|
63
|
+
var _a;
|
|
64
|
+
return (_a = document.getElementById('file-upload')) === null || _a === void 0 ? void 0 : _a.click();
|
|
65
|
+
},
|
|
66
|
+
children: [jsxRuntime.jsx("div", {
|
|
67
|
+
className: "structura-upload-icon",
|
|
68
|
+
children: jsxRuntime.jsx("svg", {
|
|
69
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
70
|
+
fill: "none",
|
|
71
|
+
viewBox: "0 0 24 24",
|
|
72
|
+
stroke: "currentColor",
|
|
73
|
+
children: jsxRuntime.jsx("path", {
|
|
74
|
+
strokeLinecap: "round",
|
|
75
|
+
strokeLinejoin: "round",
|
|
76
|
+
strokeWidth: 2,
|
|
77
|
+
d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}), jsxRuntime.jsx("h3", {
|
|
81
|
+
className: "structura-upload-text",
|
|
82
|
+
children: "Drop PDF Here or Click to Upload"
|
|
83
|
+
}), jsxRuntime.jsx("p", {
|
|
84
|
+
className: "structura-upload-subtext",
|
|
85
|
+
children: "Drag and drop your PDF document here, or click the button below to browse files"
|
|
86
|
+
}), jsxRuntime.jsxs("button", {
|
|
87
|
+
className: "structura-upload-button",
|
|
88
|
+
children: ["Upload Document", jsxRuntime.jsx("input", {
|
|
89
|
+
type: "file",
|
|
90
|
+
id: "file-upload",
|
|
91
|
+
accept: "application/pdf",
|
|
92
|
+
onChange: e => {
|
|
93
|
+
// console.log('!!! [PdfDocumentViewer] File input change event');
|
|
94
|
+
if (e.target.files && e.target.files[0]) {
|
|
95
|
+
const file = e.target.files[0];
|
|
96
|
+
// console.log('!!! [PdfDocumentViewer] File selected:', file.name, file.type);
|
|
97
|
+
onFileUpload(file);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
style: {
|
|
101
|
+
display: 'none'
|
|
102
|
+
}
|
|
103
|
+
})]
|
|
104
|
+
}), jsxRuntime.jsx("p", {
|
|
105
|
+
className: "structura-format-text",
|
|
106
|
+
children: "Supported format: PDF only"
|
|
107
|
+
})]
|
|
108
|
+
});
|
|
109
|
+
if (!fileUrl) {
|
|
110
|
+
return renderUploadArea();
|
|
111
|
+
}
|
|
112
|
+
// Let parent ScrollArea handle scrolling. Removed overflow-y-auto and maxHeight here.
|
|
113
|
+
return jsxRuntime.jsxs("div", {
|
|
114
|
+
className: "w-full relative",
|
|
115
|
+
children: [" ", jsxRuntime.jsxs("div", {
|
|
116
|
+
className: "relative w-full",
|
|
117
|
+
children: [jsxRuntime.jsxs("div", {
|
|
118
|
+
className: "sticky top-0 z-10 float-right mr-4 mt-4",
|
|
119
|
+
style: {
|
|
120
|
+
right: 'calc(50% - 300px + 1rem)'
|
|
121
|
+
},
|
|
122
|
+
children: [" ", jsxRuntime.jsx("button", {
|
|
123
|
+
onClick: onRemovePDF,
|
|
124
|
+
className: "p-2 bg-white rounded-full shadow-lg mr-2 text-red-500 hover:text-red-700 hover:bg-gray-50 transition-colors",
|
|
125
|
+
title: "Remove PDF",
|
|
126
|
+
children: jsxRuntime.jsx("svg", {
|
|
127
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
128
|
+
className: "h-6 w-6",
|
|
129
|
+
fill: "none",
|
|
130
|
+
viewBox: "0 0 24 24",
|
|
131
|
+
stroke: "currentColor",
|
|
132
|
+
children: jsxRuntime.jsx("path", {
|
|
133
|
+
strokeLinecap: "round",
|
|
134
|
+
strokeLinejoin: "round",
|
|
135
|
+
strokeWidth: 2,
|
|
136
|
+
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
})]
|
|
140
|
+
}), jsxRuntime.jsx(PdfComponents.Document, {
|
|
141
|
+
file: fileUrl,
|
|
142
|
+
onLoadSuccess: ({
|
|
143
|
+
numPages
|
|
144
|
+
}) => {
|
|
145
|
+
// console.log('!!! [PdfDocumentViewer] PDF loaded successfully with', numPages, 'pages');
|
|
146
|
+
onLoadSuccess(numPages);
|
|
147
|
+
},
|
|
148
|
+
className: "flex flex-col w-full",
|
|
149
|
+
children: allowedPages.map(pageNum => {
|
|
150
|
+
var _a;
|
|
151
|
+
const pageIndex = pageNum - 1; // pageNum is 1-indexed
|
|
152
|
+
// Assuming jsonData.children is an array of page blocks, ordered by page number.
|
|
153
|
+
const currentPageData = (_a = jsonData === null || jsonData === void 0 ? void 0 : jsonData.children) === null || _a === void 0 ? void 0 : _a[pageIndex];
|
|
154
|
+
// console.log(`[PdfDocumentViewer] Page ${pageNum}: Attempting to get data from jsonData.children[${pageIndex}]. currentPageData found:`, !!currentPageData);
|
|
155
|
+
// Optional: Validate if it's a 'Page' type block and log a warning if not.
|
|
156
|
+
// This helps ensure that the data structure assumption holds.
|
|
157
|
+
if (currentPageData && currentPageData.block_type !== "Page") ;
|
|
158
|
+
const renderBboxes = () => {
|
|
159
|
+
// console.log(`[PdfDocumentViewer] renderBboxes for page ${pageNum}: hasCurrentPageData=${!!currentPageData}, hasChildren=${!!currentPageData?.children}, hasScale=${!!pageScales[pageNum]}`);
|
|
160
|
+
if (!currentPageData || !currentPageData.children || !pageScales[pageNum]) {
|
|
161
|
+
if (!pageScales[pageNum]) console.warn(`[PdfDocumentViewer] No scale for page ${pageNum} yet.`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
const scale = pageScales[pageNum];
|
|
165
|
+
// console.log(`[PdfDocumentViewer] Page ${pageNum}: Using scale ${scale}`);
|
|
166
|
+
let bboxesToRender = [];
|
|
167
|
+
function collectBboxes(blocks, path = "") {
|
|
168
|
+
blocks.forEach((block, index) => {
|
|
169
|
+
const currentPath = `${path}/${block.block_type}[${index}](${block.id})`;
|
|
170
|
+
// Assuming block.polygon is number[][] (array of points)
|
|
171
|
+
const points = block.polygon;
|
|
172
|
+
if (points && Array.isArray(points) && points.length >= 2 && block.block_type !== "Page") {
|
|
173
|
+
// Calculate bbox from points
|
|
174
|
+
const x_coords = points.map(p => p[0]);
|
|
175
|
+
const y_coords = points.map(p => p[1]);
|
|
176
|
+
let x_min = Math.min(...x_coords);
|
|
177
|
+
let y_min = Math.min(...y_coords);
|
|
178
|
+
let x_max = Math.max(...x_coords);
|
|
179
|
+
let y_max = Math.max(...y_coords);
|
|
180
|
+
if (x_max <= x_min || y_max <= y_min) {
|
|
181
|
+
console.warn(`[PdfDocumentViewer] Page ${pageNum}: Invalid bbox for block ${block.id} (path: ${currentPath}) - [${x_min}, ${y_min}, ${x_max}, ${y_max}]`);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const style = {
|
|
185
|
+
position: 'absolute',
|
|
186
|
+
left: `${x_min * scale}px`,
|
|
187
|
+
top: `${y_min * scale}px`,
|
|
188
|
+
width: `${(x_max - x_min) * scale}px`,
|
|
189
|
+
height: `${(y_max - y_min) * scale}px`,
|
|
190
|
+
border: `1px solid ${block.id === selectedBboxId ? 'red' : 'rgba(0, 100, 255, 0.5)'}`,
|
|
191
|
+
backgroundColor: `${block.id === selectedBboxId ? 'rgba(255, 0, 0, 0.2)' : 'rgba(0, 100, 255, 0.1)'}`,
|
|
192
|
+
pointerEvents: 'auto',
|
|
193
|
+
boxSizing: 'border-box',
|
|
194
|
+
cursor: 'pointer',
|
|
195
|
+
zIndex: 10 // Ensure bboxes are on top
|
|
196
|
+
};
|
|
197
|
+
if (bboxesToRender.length < 5 || block.id === selectedBboxId) {
|
|
198
|
+
console.log(`[PdfDocumentViewer] Page ${pageNum}: Rendering bbox for ${block.id} (path: ${currentPath})`, {
|
|
199
|
+
x_min,
|
|
200
|
+
y_min,
|
|
201
|
+
x_max,
|
|
202
|
+
y_max,
|
|
203
|
+
scale,
|
|
204
|
+
finalStyle: style
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
bboxesToRender.push(jsxRuntime.jsx("div", {
|
|
208
|
+
style: style,
|
|
209
|
+
title: `${block.id} (${block.block_type})`,
|
|
210
|
+
onClick: e => {
|
|
211
|
+
e.stopPropagation(); // Prevent clicks from bubbling to parent elements
|
|
212
|
+
if (onPdfBboxClick) {
|
|
213
|
+
// console.log(`[PdfDocumentViewer] Bbox clicked: ${block.id}`);
|
|
214
|
+
onPdfBboxClick(block.id);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}, block.id));
|
|
218
|
+
}
|
|
219
|
+
if (block.children) {
|
|
220
|
+
collectBboxes(block.children, currentPath);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (currentPageData.children) {
|
|
225
|
+
// console.log(`[PdfDocumentViewer] Page ${pageNum}: Starting collectBboxes for ${currentPageData.children.length} top-level blocks.`);
|
|
226
|
+
collectBboxes(currentPageData.children);
|
|
227
|
+
}
|
|
228
|
+
// console.log(`[PdfDocumentViewer] Page ${pageNum}: Collected ${bboxesToRender.length} bboxes to render.`);
|
|
229
|
+
return bboxesToRender;
|
|
230
|
+
};
|
|
231
|
+
return (
|
|
232
|
+
// The parent div for a page and its bboxes.
|
|
233
|
+
// It needs a defined width matching the page's render width for correct bbox positioning.
|
|
234
|
+
// Removed 'flex justify-center' to avoid x-offset issues with absolute bboxes.
|
|
235
|
+
// Bboxes are positioned relative to this div.
|
|
236
|
+
jsxRuntime.jsxs("div", {
|
|
237
|
+
id: `pdf-page-container-${pageNum}`,
|
|
238
|
+
className: "relative mb-4 shadow-lg mx-auto" // mx-auto will center it if parent is wider
|
|
239
|
+
,
|
|
240
|
+
style: {
|
|
241
|
+
width: `${pageScales[pageNum] ? 600 : 'auto'}px`
|
|
242
|
+
},
|
|
243
|
+
children: [jsxRuntime.jsx(PdfComponents.Page, {
|
|
244
|
+
pageNumber: pageNum,
|
|
245
|
+
width: 600,
|
|
246
|
+
onRenderSuccess: pageProxy => {
|
|
247
|
+
const viewport = pageProxy.getViewport({
|
|
248
|
+
scale: 1
|
|
249
|
+
});
|
|
250
|
+
const newScale = 600 / viewport.width;
|
|
251
|
+
console.log(`[PdfDocumentViewer] Page ${pageNum}: onRenderSuccess. Natural width: ${viewport.width}, calculated scale: ${newScale}`);
|
|
252
|
+
if (pageScales[pageNum] !== newScale) {
|
|
253
|
+
setPageScales(prev => ({
|
|
254
|
+
...prev,
|
|
255
|
+
[pageNum]: newScale
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
onRenderError: error => console.error(`[PdfDocumentViewer] Page ${pageNum}: onRenderError`, error),
|
|
260
|
+
className: "pdf-page-canvas" // Add a class for potential targeting
|
|
261
|
+
}), pageScales[pageNum] ? renderBboxes() : jsxRuntime.jsxs("div", {
|
|
262
|
+
style: {
|
|
263
|
+
position: 'absolute',
|
|
264
|
+
top: '50%',
|
|
265
|
+
left: '50%',
|
|
266
|
+
transform: 'translate(-50%, -50%)',
|
|
267
|
+
color: 'orange',
|
|
268
|
+
width: '200px',
|
|
269
|
+
textAlign: 'center'
|
|
270
|
+
},
|
|
271
|
+
children: ["Loading page ", pageNum, "..."]
|
|
272
|
+
})]
|
|
273
|
+
}, pageNum)
|
|
274
|
+
);
|
|
275
|
+
})
|
|
276
|
+
}, `${fileUrl}`)]
|
|
277
|
+
})]
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
exports.default = PdfDocumentViewer;
|