@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.
Files changed (95) hide show
  1. package/PRODUCTION_ARCHITECTURE.md +511 -0
  2. package/README.md +379 -0
  3. package/SAVE_FUNCTIONALITY_COMPLETE.md +448 -0
  4. package/dist/cjs/EditableContent.js +150 -0
  5. package/dist/cjs/HtmlViewer.js +587 -0
  6. package/dist/cjs/PdfComponents.js +16 -0
  7. package/dist/cjs/PdfDocumentViewer.js +281 -0
  8. package/dist/cjs/Structura.js +806 -0
  9. package/dist/cjs/Table.js +164 -0
  10. package/dist/cjs/TableCell.js +115 -0
  11. package/dist/cjs/accuracyMetrics.js +39 -0
  12. package/dist/cjs/helpers/preprocessData.js +143 -0
  13. package/dist/cjs/index.js +7 -0
  14. package/dist/cjs/lib/polyfills.js +15 -0
  15. package/dist/cjs/lib/utils.js +10 -0
  16. package/dist/cjs/node_modules/react-icons/fa/index.esm.js +14 -0
  17. package/dist/cjs/node_modules/react-icons/lib/esm/iconBase.js +69 -0
  18. package/dist/cjs/node_modules/react-icons/lib/esm/iconContext.js +15 -0
  19. package/dist/cjs/polyfills.js +19 -0
  20. package/dist/cjs/route.js +102 -0
  21. package/dist/cjs/styles.css +7 -0
  22. package/dist/cjs/styles.css.map +1 -0
  23. package/dist/cjs/ui/badge.js +34 -0
  24. package/dist/cjs/ui/button.js +71 -0
  25. package/dist/cjs/ui/card.js +86 -0
  26. package/dist/cjs/ui/progress.js +45 -0
  27. package/dist/cjs/ui/scroll-area.js +62 -0
  28. package/dist/cjs/ui/tabs.js +60 -0
  29. package/dist/cjs/worker.js +36 -0
  30. package/dist/esm/EditableContent.js +161 -0
  31. package/dist/esm/HtmlViewer.js +640 -0
  32. package/dist/esm/PdfComponents.js +21 -0
  33. package/dist/esm/PdfDocumentViewer.js +294 -0
  34. package/dist/esm/Structura.js +951 -0
  35. package/dist/esm/Table.js +182 -0
  36. package/dist/esm/TableCell.js +122 -0
  37. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +305 -0
  38. package/dist/esm/accuracyMetrics.js +41 -0
  39. package/dist/esm/helpers/preprocessData.js +152 -0
  40. package/dist/esm/index.js +1 -0
  41. package/dist/esm/lib/polyfills.js +13 -0
  42. package/dist/esm/lib/utils.js +8 -0
  43. package/dist/esm/node_modules/react-icons/fa/index.esm.js +11 -0
  44. package/dist/esm/node_modules/react-icons/lib/esm/iconBase.js +66 -0
  45. package/dist/esm/node_modules/react-icons/lib/esm/iconContext.js +12 -0
  46. package/dist/esm/polyfills.js +17 -0
  47. package/dist/esm/route.js +154 -0
  48. package/dist/esm/styles.css +7 -0
  49. package/dist/esm/styles.css.map +1 -0
  50. package/dist/esm/types/EditableContent.d.ts +9 -0
  51. package/dist/esm/types/HtmlViewer.d.ts +10 -0
  52. package/dist/esm/types/PdfComponents.d.ts +35 -0
  53. package/dist/esm/types/PdfDocumentViewer.d.ts +22 -0
  54. package/dist/esm/types/Structura.d.ts +11 -0
  55. package/dist/esm/types/Table.d.ts +12 -0
  56. package/dist/esm/types/TableCell.d.ts +13 -0
  57. package/dist/esm/types/accuracy.d.ts +23 -0
  58. package/dist/esm/types/accuracyMetrics.d.ts +5 -0
  59. package/dist/esm/types/helpers/flattenJSON.d.ts +1 -0
  60. package/dist/esm/types/helpers/hardMerging.d.ts +2 -0
  61. package/dist/esm/types/helpers/index.d.ts +6 -0
  62. package/dist/esm/types/helpers/jsonToHtml.d.ts +40 -0
  63. package/dist/esm/types/helpers/preprocessData.d.ts +3 -0
  64. package/dist/esm/types/helpers/removeMetadata.d.ts +1 -0
  65. package/dist/esm/types/helpers/tableProcessor.d.ts +1 -0
  66. package/dist/esm/types/index.d.ts +3 -0
  67. package/dist/esm/types/lib/polyfills.d.ts +1 -0
  68. package/dist/esm/types/lib/utils.d.ts +2 -0
  69. package/dist/esm/types/polyfills.d.ts +1 -0
  70. package/dist/esm/types/route.d.ts +45 -0
  71. package/dist/esm/types/test-app/src/App.d.ts +4 -0
  72. package/dist/esm/types/test-app/src/main.d.ts +1 -0
  73. package/dist/esm/types/test-app/vite.config.d.ts +2 -0
  74. package/dist/esm/types/types.d.ts +23 -0
  75. package/dist/esm/types/ui/alert.d.ts +8 -0
  76. package/dist/esm/types/ui/badge.d.ts +9 -0
  77. package/dist/esm/types/ui/button.d.ts +11 -0
  78. package/dist/esm/types/ui/card.d.ts +8 -0
  79. package/dist/esm/types/ui/progress.d.ts +6 -0
  80. package/dist/esm/types/ui/scroll-area.d.ts +5 -0
  81. package/dist/esm/types/ui/skeleton.d.ts +2 -0
  82. package/dist/esm/types/ui/tabs.d.ts +7 -0
  83. package/dist/esm/types/worker.d.ts +1 -0
  84. package/dist/esm/ui/badge.js +31 -0
  85. package/dist/esm/ui/button.js +50 -0
  86. package/dist/esm/ui/card.js +67 -0
  87. package/dist/esm/ui/progress.js +26 -0
  88. package/dist/esm/ui/scroll-area.js +45 -0
  89. package/dist/esm/ui/tabs.js +39 -0
  90. package/dist/esm/worker.js +50 -0
  91. package/dist/index.d.ts +38 -0
  92. package/package.json +85 -0
  93. package/server/README.md +203 -0
  94. package/server/db.js +142 -0
  95. 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;