@tfw.in/structura-lib 0.2.0 → 0.2.2
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/README.md +72 -323
- package/dist/cjs/EditableContent.js +46 -18
- package/dist/cjs/HtmlViewer.js +238 -85
- package/dist/cjs/MathRenderer.js +88 -0
- package/dist/cjs/PdfDocumentViewer.js +1 -1
- package/dist/cjs/SemanticTagParser.js +189 -0
- package/dist/cjs/SemanticTagRenderer.js +135 -0
- package/dist/cjs/Structura.js +49 -76
- package/dist/cjs/Table.js +75 -8
- package/dist/cjs/TableCell.js +34 -10
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/node_modules/react-icons/fa/index.esm.js +6 -0
- package/dist/cjs/styles.css +2 -4
- package/dist/cjs/styles.css.map +1 -1
- package/dist/esm/EditableContent.js +51 -19
- package/dist/esm/HtmlViewer.js +287 -103
- package/dist/esm/MathRenderer.js +85 -0
- package/dist/esm/PdfDocumentViewer.js +1 -1
- package/dist/esm/SemanticTagParser.js +187 -0
- package/dist/esm/SemanticTagRenderer.js +140 -0
- package/dist/esm/Structura.js +57 -80
- package/dist/esm/Table.js +85 -8
- package/dist/esm/TableCell.js +34 -6
- package/dist/esm/index.js +3 -0
- package/dist/esm/node_modules/react-icons/fa/index.esm.js +5 -1
- package/dist/esm/styles.css +2 -4
- package/dist/esm/styles.css.map +1 -1
- package/dist/esm/types/DocumentOutline.d.ts +7 -0
- package/dist/esm/types/EditableContent.d.ts +8 -1
- package/dist/esm/types/HtmlViewer.d.ts +9 -2
- package/dist/esm/types/MathRenderer.d.ts +25 -0
- package/dist/esm/types/SemanticTagParser.d.ts +33 -0
- package/dist/esm/types/SemanticTagRenderer.d.ts +17 -0
- package/dist/esm/types/Structura.d.ts +13 -8
- package/dist/esm/types/Table.d.ts +4 -1
- package/dist/esm/types/TableCell.d.ts +7 -1
- package/dist/esm/types/helpers/index.d.ts +0 -1
- package/dist/esm/types/index.d.ts +3 -0
- package/dist/esm/types/test-app/src/App.d.ts +1 -2
- package/dist/index.d.ts +90 -10
- package/package.json +9 -16
- package/PRODUCTION_ARCHITECTURE.md +0 -511
- package/SAVE_FUNCTIONALITY_COMPLETE.md +0 -448
- package/dist/cjs/ui/badge.js +0 -34
- package/dist/esm/types/helpers/jsonToHtml.d.ts +0 -40
- package/dist/esm/ui/badge.js +0 -31
- package/server/README.md +0 -203
- package/server/db.js +0 -142
- package/server/server.js +0 -165
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import katex from 'katex';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders LaTeX math expressions in HTML content using KaTeX.
|
|
7
|
+
* Supports both inline ($...$) and display ($$...$$) math.
|
|
8
|
+
*/
|
|
9
|
+
// Regex patterns for math delimiters
|
|
10
|
+
var DISPLAY_MATH_REGEX = /\$\$([\s\S]*?)\$\$/g;
|
|
11
|
+
var INLINE_MATH_REGEX = /\$([^\$\n]+?)\$/g;
|
|
12
|
+
/**
|
|
13
|
+
* Render a single LaTeX expression to HTML using KaTeX
|
|
14
|
+
*/
|
|
15
|
+
function renderLatex(latex, displayMode) {
|
|
16
|
+
try {
|
|
17
|
+
return katex.renderToString(latex, {
|
|
18
|
+
displayMode: displayMode,
|
|
19
|
+
throwOnError: false,
|
|
20
|
+
errorColor: "#cc0000",
|
|
21
|
+
strict: false,
|
|
22
|
+
trust: true,
|
|
23
|
+
macros: {
|
|
24
|
+
"\\leq": "\\le",
|
|
25
|
+
"\\geq": "\\ge"
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.warn("KaTeX render error:", error);
|
|
30
|
+
// Return the original with error styling
|
|
31
|
+
return "<span class=\"katex-error\" style=\"color: #cc0000;\">".concat(latex, "</span>");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Process HTML content and render all math expressions
|
|
36
|
+
*/
|
|
37
|
+
function renderMathInHtml(html) {
|
|
38
|
+
if (!html) return "";
|
|
39
|
+
// First, handle display math ($$...$$)
|
|
40
|
+
var result = html.replace(DISPLAY_MATH_REGEX, function (match, latex) {
|
|
41
|
+
return renderLatex(latex.trim(), true);
|
|
42
|
+
});
|
|
43
|
+
// Then, handle inline math ($...$)
|
|
44
|
+
// The $...$ pattern with closing $ is always math, not currency
|
|
45
|
+
result = result.replace(INLINE_MATH_REGEX, function (match, latex) {
|
|
46
|
+
return renderLatex(latex.trim(), false);
|
|
47
|
+
});
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if content contains any math expressions
|
|
52
|
+
*/
|
|
53
|
+
function containsMath(html) {
|
|
54
|
+
if (!html) return false;
|
|
55
|
+
return DISPLAY_MATH_REGEX.test(html) || INLINE_MATH_REGEX.test(html);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* React component that renders HTML with math expressions
|
|
59
|
+
*/
|
|
60
|
+
function MathContent(_ref) {
|
|
61
|
+
var html = _ref.html,
|
|
62
|
+
_ref$className = _ref.className,
|
|
63
|
+
className = _ref$className === void 0 ? "" : _ref$className,
|
|
64
|
+
_ref$as = _ref.as,
|
|
65
|
+
Component = _ref$as === void 0 ? "span" : _ref$as;
|
|
66
|
+
var renderedHtml = useMemo(function () {
|
|
67
|
+
return renderMathInHtml(html);
|
|
68
|
+
}, [html]);
|
|
69
|
+
return jsx(Component, {
|
|
70
|
+
className: className,
|
|
71
|
+
dangerouslySetInnerHTML: {
|
|
72
|
+
__html: renderedHtml
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Hook to get rendered math HTML
|
|
78
|
+
*/
|
|
79
|
+
function useMathHtml(html) {
|
|
80
|
+
return useMemo(function () {
|
|
81
|
+
return renderMathInHtml(html);
|
|
82
|
+
}, [html]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { MathContent, containsMath, MathContent as default, renderMathInHtml, useMathHtml };
|
|
@@ -177,7 +177,7 @@ function PdfDocumentViewer(_ref2) {
|
|
|
177
177
|
var currentPath = "".concat(path, "/").concat(block.block_type, "[").concat(index, "](").concat(block.id, ")");
|
|
178
178
|
// Assuming block.polygon is number[][] (array of points)
|
|
179
179
|
var points = block.polygon;
|
|
180
|
-
if (points && Array.isArray(points) && points.length >= 2 && block.block_type !== "Page") {
|
|
180
|
+
if (points && Array.isArray(points) && points.length >= 2 && block.block_type !== "Page" && block.block_type !== "TableCell") {
|
|
181
181
|
// Calculate bbox from points
|
|
182
182
|
var x_coords = points.map(function (p) {
|
|
183
183
|
return p[0];
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Semantic Tag Parser for SOP/Batch Record domain tags
|
|
2
|
+
// Supports: MeasurementTag, HiddenMeasurementTag, ValueTag, DateTimeTag, FileTag, ImageTag
|
|
3
|
+
// Regular expression patterns for tag detection
|
|
4
|
+
// Standard tag: [[value][type:TYPE][attr:value]...]
|
|
5
|
+
// Hidden tag: {[value][type:TYPE][attr:value]...]}
|
|
6
|
+
var STANDARD_TAG_PATTERN = /\[\[([^\]]+)\](\[([^\]]+)\])*\]/g;
|
|
7
|
+
var HIDDEN_TAG_PATTERN = /\{\[([^\]]+)\](\[([^\]]+)\])*\]\}/g;
|
|
8
|
+
// Parse a single tag's attribute string like "[type:MEASUREMENT][uom:mL/min][id:abc-123]"
|
|
9
|
+
function parseTagAttributes(attributeStr) {
|
|
10
|
+
var attributes = {};
|
|
11
|
+
var type = 'VALUE'; // Default type
|
|
12
|
+
// Match all [key:value] pairs
|
|
13
|
+
var attrPattern = /\[([^:\]]+):([^\]]+)\]/g;
|
|
14
|
+
var match;
|
|
15
|
+
while ((match = attrPattern.exec(attributeStr)) !== null) {
|
|
16
|
+
var key = match[1].toLowerCase();
|
|
17
|
+
var value = match[2];
|
|
18
|
+
switch (key) {
|
|
19
|
+
case 'type':
|
|
20
|
+
type = value.toUpperCase();
|
|
21
|
+
break;
|
|
22
|
+
case 'uom':
|
|
23
|
+
attributes.uom = value;
|
|
24
|
+
break;
|
|
25
|
+
case 'id':
|
|
26
|
+
attributes.id = value;
|
|
27
|
+
break;
|
|
28
|
+
case 'format':
|
|
29
|
+
attributes.format = value;
|
|
30
|
+
break;
|
|
31
|
+
case 'filter':
|
|
32
|
+
attributes.filter = value;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
type: type,
|
|
38
|
+
attributes: attributes
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Parse a single tag match
|
|
42
|
+
function parseTag(match, isHidden) {
|
|
43
|
+
var rawMatch = match[0];
|
|
44
|
+
var startIndex = match.index;
|
|
45
|
+
var endIndex = startIndex + rawMatch.length;
|
|
46
|
+
// Extract the value (first bracket content) and attributes (remaining brackets)
|
|
47
|
+
var innerContent;
|
|
48
|
+
if (isHidden) {
|
|
49
|
+
// Remove {[ and ]} wrapper
|
|
50
|
+
innerContent = rawMatch.slice(2, -2);
|
|
51
|
+
} else {
|
|
52
|
+
// Remove [[ and ]] wrapper (but there might be more brackets for attributes)
|
|
53
|
+
innerContent = rawMatch.slice(2, -1);
|
|
54
|
+
}
|
|
55
|
+
// Split by ][ to get value and attributes
|
|
56
|
+
var parts = innerContent.split('][');
|
|
57
|
+
var value = parts[0];
|
|
58
|
+
var attributeStr = parts.length > 1 ? '[' + parts.slice(1).join('][') + ']' : '';
|
|
59
|
+
var _parseTagAttributes = parseTagAttributes(attributeStr),
|
|
60
|
+
type = _parseTagAttributes.type,
|
|
61
|
+
attributes = _parseTagAttributes.attributes;
|
|
62
|
+
// Adjust type for hidden tags
|
|
63
|
+
var finalType = isHidden ? 'HIDDEN_MEASUREMENT' : type;
|
|
64
|
+
return {
|
|
65
|
+
type: finalType,
|
|
66
|
+
value: value,
|
|
67
|
+
rawMatch: rawMatch,
|
|
68
|
+
startIndex: startIndex,
|
|
69
|
+
endIndex: endIndex,
|
|
70
|
+
attributes: attributes,
|
|
71
|
+
isHidden: isHidden
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Main parsing function
|
|
75
|
+
function parseSemanticTags(text) {
|
|
76
|
+
var tags = [];
|
|
77
|
+
// Find all standard tags
|
|
78
|
+
var match;
|
|
79
|
+
var standardPattern = new RegExp(STANDARD_TAG_PATTERN.source, 'g');
|
|
80
|
+
while ((match = standardPattern.exec(text)) !== null) {
|
|
81
|
+
tags.push(parseTag(match, false));
|
|
82
|
+
}
|
|
83
|
+
// Find all hidden tags
|
|
84
|
+
var hiddenPattern = new RegExp(HIDDEN_TAG_PATTERN.source, 'g');
|
|
85
|
+
while ((match = hiddenPattern.exec(text)) !== null) {
|
|
86
|
+
tags.push(parseTag(match, true));
|
|
87
|
+
}
|
|
88
|
+
// Sort tags by start index
|
|
89
|
+
tags.sort(function (a, b) {
|
|
90
|
+
return a.startIndex - b.startIndex;
|
|
91
|
+
});
|
|
92
|
+
// Build segments
|
|
93
|
+
var segments = [];
|
|
94
|
+
var currentIndex = 0;
|
|
95
|
+
for (var _i = 0, _tags = tags; _i < _tags.length; _i++) {
|
|
96
|
+
var tag = _tags[_i];
|
|
97
|
+
// Add text before this tag
|
|
98
|
+
if (tag.startIndex > currentIndex) {
|
|
99
|
+
segments.push({
|
|
100
|
+
type: 'text',
|
|
101
|
+
content: text.slice(currentIndex, tag.startIndex)
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Add the tag segment (skip hidden tags in output)
|
|
105
|
+
if (!tag.isHidden) {
|
|
106
|
+
segments.push({
|
|
107
|
+
type: 'tag',
|
|
108
|
+
content: tag.value,
|
|
109
|
+
tag: tag
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
currentIndex = tag.endIndex;
|
|
113
|
+
}
|
|
114
|
+
// Add remaining text after last tag
|
|
115
|
+
if (currentIndex < text.length) {
|
|
116
|
+
segments.push({
|
|
117
|
+
type: 'text',
|
|
118
|
+
content: text.slice(currentIndex)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
originalText: text,
|
|
123
|
+
tags: tags,
|
|
124
|
+
segments: segments
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Check if text contains any semantic tags
|
|
128
|
+
function hasSemanticTags(text) {
|
|
129
|
+
if (!text) return false;
|
|
130
|
+
return STANDARD_TAG_PATTERN.test(text) || HIDDEN_TAG_PATTERN.test(text);
|
|
131
|
+
}
|
|
132
|
+
// Get tag type display info (for styling)
|
|
133
|
+
function getTagTypeInfo(type) {
|
|
134
|
+
switch (type) {
|
|
135
|
+
case 'MEASUREMENT':
|
|
136
|
+
return {
|
|
137
|
+
color: 'text-blue-700',
|
|
138
|
+
bgColor: 'bg-blue-100 border-blue-300',
|
|
139
|
+
icon: '📏',
|
|
140
|
+
label: 'Measurement'
|
|
141
|
+
};
|
|
142
|
+
case 'VALUE':
|
|
143
|
+
return {
|
|
144
|
+
color: 'text-emerald-700',
|
|
145
|
+
bgColor: 'bg-emerald-100 border-emerald-300',
|
|
146
|
+
icon: '📝',
|
|
147
|
+
label: 'Value'
|
|
148
|
+
};
|
|
149
|
+
case 'FILE':
|
|
150
|
+
return {
|
|
151
|
+
color: 'text-purple-700',
|
|
152
|
+
bgColor: 'bg-purple-100 border-purple-300',
|
|
153
|
+
icon: '📄',
|
|
154
|
+
label: 'File'
|
|
155
|
+
};
|
|
156
|
+
case 'IMAGE':
|
|
157
|
+
return {
|
|
158
|
+
color: 'text-pink-700',
|
|
159
|
+
bgColor: 'bg-pink-100 border-pink-300',
|
|
160
|
+
icon: '🖼️',
|
|
161
|
+
label: 'Image'
|
|
162
|
+
};
|
|
163
|
+
case 'DATETIME':
|
|
164
|
+
return {
|
|
165
|
+
color: 'text-orange-700',
|
|
166
|
+
bgColor: 'bg-orange-100 border-orange-300',
|
|
167
|
+
icon: '📅',
|
|
168
|
+
label: 'DateTime'
|
|
169
|
+
};
|
|
170
|
+
case 'HIDDEN_MEASUREMENT':
|
|
171
|
+
return {
|
|
172
|
+
color: 'text-gray-500',
|
|
173
|
+
bgColor: 'bg-gray-100 border-gray-300',
|
|
174
|
+
icon: '👁️🗨️',
|
|
175
|
+
label: 'Hidden'
|
|
176
|
+
};
|
|
177
|
+
default:
|
|
178
|
+
return {
|
|
179
|
+
color: 'text-gray-700',
|
|
180
|
+
bgColor: 'bg-gray-100 border-gray-300',
|
|
181
|
+
icon: '🏷️',
|
|
182
|
+
label: 'Tag'
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { getTagTypeInfo, hasSemanticTags, parseSemanticTags };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { slicedToArray as _slicedToArray } from './_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { hasSemanticTags, parseSemanticTags, getTagTypeInfo } from './SemanticTagParser.js';
|
|
5
|
+
|
|
6
|
+
// Individual tag badge component
|
|
7
|
+
function TagBadge(_ref) {
|
|
8
|
+
var tag = _ref.tag,
|
|
9
|
+
_ref$showTooltip = _ref.showTooltip,
|
|
10
|
+
showTooltip = _ref$showTooltip === void 0 ? true : _ref$showTooltip,
|
|
11
|
+
onClick = _ref.onClick;
|
|
12
|
+
var _useState = useState(false),
|
|
13
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
14
|
+
isHovered = _useState2[0],
|
|
15
|
+
setIsHovered = _useState2[1];
|
|
16
|
+
var typeInfo = getTagTypeInfo(tag.type);
|
|
17
|
+
return jsxs("span", {
|
|
18
|
+
className: "relative inline-flex items-center gap-1 px-1.5 py-0.5 mx-0.5 rounded border text-xs font-medium cursor-default transition-all\n ".concat(typeInfo.bgColor, " ").concat(typeInfo.color, "\n ").concat(onClick ? 'cursor-pointer hover:shadow-md' : '', "\n ").concat(isHovered ? 'ring-2 ring-offset-1 ring-blue-400' : ''),
|
|
19
|
+
onMouseEnter: function onMouseEnter() {
|
|
20
|
+
return setIsHovered(true);
|
|
21
|
+
},
|
|
22
|
+
onMouseLeave: function onMouseLeave() {
|
|
23
|
+
return setIsHovered(false);
|
|
24
|
+
},
|
|
25
|
+
onClick: onClick,
|
|
26
|
+
children: [jsx("span", {
|
|
27
|
+
className: "text-[10px]",
|
|
28
|
+
children: typeInfo.icon
|
|
29
|
+
}), jsx("span", {
|
|
30
|
+
children: tag.value
|
|
31
|
+
}), tag.attributes.uom && jsx("span", {
|
|
32
|
+
className: "text-[10px] opacity-75 ml-0.5",
|
|
33
|
+
children: tag.attributes.uom
|
|
34
|
+
}), showTooltip && isHovered && jsx("div", {
|
|
35
|
+
className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50 pointer-events-none",
|
|
36
|
+
children: jsxs("div", {
|
|
37
|
+
className: "bg-gray-900 text-white text-xs rounded-lg px-3 py-2 shadow-lg whitespace-nowrap",
|
|
38
|
+
children: [jsxs("div", {
|
|
39
|
+
className: "font-semibold mb-1",
|
|
40
|
+
children: [typeInfo.label, " Tag"]
|
|
41
|
+
}), jsxs("div", {
|
|
42
|
+
className: "space-y-0.5 text-gray-300",
|
|
43
|
+
children: [jsxs("div", {
|
|
44
|
+
children: ["Value: ", jsx("span", {
|
|
45
|
+
className: "text-white",
|
|
46
|
+
children: tag.value
|
|
47
|
+
})]
|
|
48
|
+
}), tag.attributes.uom && jsxs("div", {
|
|
49
|
+
children: ["Unit: ", jsx("span", {
|
|
50
|
+
className: "text-white",
|
|
51
|
+
children: tag.attributes.uom
|
|
52
|
+
})]
|
|
53
|
+
}), tag.attributes.id && jsxs("div", {
|
|
54
|
+
className: "text-[10px] text-gray-400 truncate max-w-[200px]",
|
|
55
|
+
children: ["ID: ", tag.attributes.id]
|
|
56
|
+
}), tag.attributes.format && jsxs("div", {
|
|
57
|
+
children: ["Format: ", jsx("span", {
|
|
58
|
+
className: "text-white",
|
|
59
|
+
children: tag.attributes.format
|
|
60
|
+
})]
|
|
61
|
+
})]
|
|
62
|
+
}), jsx("div", {
|
|
63
|
+
className: "absolute top-full left-1/2 -translate-x-1/2 -mt-px",
|
|
64
|
+
children: jsx("div", {
|
|
65
|
+
className: "border-4 border-transparent border-t-gray-900"
|
|
66
|
+
})
|
|
67
|
+
})]
|
|
68
|
+
})
|
|
69
|
+
})]
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Main renderer component
|
|
73
|
+
function SemanticTagRenderer(_ref2) {
|
|
74
|
+
var content = _ref2.content,
|
|
75
|
+
_ref2$className = _ref2.className,
|
|
76
|
+
className = _ref2$className === void 0 ? '' : _ref2$className,
|
|
77
|
+
_ref2$showTooltips = _ref2.showTooltips,
|
|
78
|
+
showTooltips = _ref2$showTooltips === void 0 ? true : _ref2$showTooltips,
|
|
79
|
+
onTagClick = _ref2.onTagClick;
|
|
80
|
+
// If no semantic tags, just return the content as-is
|
|
81
|
+
if (!hasSemanticTags(content)) {
|
|
82
|
+
return jsx("span", {
|
|
83
|
+
className: className,
|
|
84
|
+
dangerouslySetInnerHTML: {
|
|
85
|
+
__html: content
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
var parsed = parseSemanticTags(content);
|
|
90
|
+
return jsx("span", {
|
|
91
|
+
className: className,
|
|
92
|
+
children: parsed.segments.map(function (segment, index) {
|
|
93
|
+
if (segment.type === 'text') {
|
|
94
|
+
// Render plain text (may contain HTML)
|
|
95
|
+
return jsx("span", {
|
|
96
|
+
dangerouslySetInnerHTML: {
|
|
97
|
+
__html: segment.content
|
|
98
|
+
}
|
|
99
|
+
}, index);
|
|
100
|
+
} else if (segment.type === 'tag' && segment.tag) {
|
|
101
|
+
// Render semantic tag badge
|
|
102
|
+
return jsx(TagBadge, {
|
|
103
|
+
tag: segment.tag,
|
|
104
|
+
showTooltip: showTooltips,
|
|
105
|
+
onClick: onTagClick ? function () {
|
|
106
|
+
return onTagClick(segment.tag);
|
|
107
|
+
} : undefined
|
|
108
|
+
}, index);
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function SmartContent(_ref3) {
|
|
115
|
+
var content = _ref3.content,
|
|
116
|
+
_ref3$className = _ref3.className,
|
|
117
|
+
className = _ref3$className === void 0 ? '' : _ref3$className,
|
|
118
|
+
_ref3$enableSemanticT = _ref3.enableSemanticTags,
|
|
119
|
+
enableSemanticTags = _ref3$enableSemanticT === void 0 ? true : _ref3$enableSemanticT,
|
|
120
|
+
_ref3$showTooltips = _ref3.showTooltips,
|
|
121
|
+
showTooltips = _ref3$showTooltips === void 0 ? true : _ref3$showTooltips,
|
|
122
|
+
onTagClick = _ref3.onTagClick;
|
|
123
|
+
if (enableSemanticTags && hasSemanticTags(content)) {
|
|
124
|
+
return jsx(SemanticTagRenderer, {
|
|
125
|
+
content: content,
|
|
126
|
+
className: className,
|
|
127
|
+
showTooltips: showTooltips,
|
|
128
|
+
onTagClick: onTagClick
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// Regular content without semantic tags
|
|
132
|
+
return jsx("span", {
|
|
133
|
+
className: className,
|
|
134
|
+
dangerouslySetInnerHTML: {
|
|
135
|
+
__html: content
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { SmartContent, SemanticTagRenderer as default };
|
package/dist/esm/Structura.js
CHANGED
|
@@ -2,14 +2,13 @@ import { slicedToArray as _slicedToArray, asyncToGenerator as _asyncToGenerator,
|
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
4
|
import { Button } from './ui/button.js';
|
|
5
|
-
import { Card,
|
|
5
|
+
import { Card, CardContent } from './ui/card.js';
|
|
6
6
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from './ui/tabs.js';
|
|
7
7
|
import * as LucideIcons from 'lucide-react';
|
|
8
8
|
import PdfDocumentViewer from './PdfDocumentViewer.js';
|
|
9
9
|
import HtmlViewer from './HtmlViewer.js';
|
|
10
10
|
import { preprocessData } from './helpers/preprocessData.js';
|
|
11
11
|
import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels';
|
|
12
|
-
import { Badge } from './ui/badge.js';
|
|
13
12
|
import { Progress } from './ui/progress.js';
|
|
14
13
|
import { ScrollArea } from './ui/scroll-area.js';
|
|
15
14
|
import { GET, POST } from './route.js';
|
|
@@ -17,15 +16,24 @@ import { GET, POST } from './route.js';
|
|
|
17
16
|
// Remove component aliases and use direct imports
|
|
18
17
|
// This will preserve the propser types
|
|
19
18
|
function Structura(_ref) {
|
|
20
|
-
var
|
|
19
|
+
var apiKey = _ref.apiKey,
|
|
20
|
+
baseUrl = _ref.baseUrl,
|
|
21
|
+
initialPdfPath = _ref.initialPdfPath,
|
|
21
22
|
initialJsonData = _ref.initialJsonData,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
_ref$editMode = _ref.editMode,
|
|
24
|
+
editMode = _ref$editMode === void 0 ? true : _ref$editMode,
|
|
25
|
+
_ref$jsonMode = _ref.jsonMode,
|
|
26
|
+
jsonMode = _ref$jsonMode === void 0 ? true : _ref$jsonMode,
|
|
27
|
+
_ref$mathRendering = _ref.mathRendering,
|
|
28
|
+
mathRendering = _ref$mathRendering === void 0 ? true : _ref$mathRendering,
|
|
29
|
+
_ref$semanticTags = _ref.semanticTags,
|
|
30
|
+
semanticTags = _ref$semanticTags === void 0 ? true : _ref$semanticTags,
|
|
31
|
+
_ref$headerFooterBadg = _ref.headerFooterBadges,
|
|
32
|
+
headerFooterBadges = _ref$headerFooterBadg === void 0 ? true : _ref$headerFooterBadg,
|
|
33
|
+
_ref$defaultViewMode = _ref.defaultViewMode,
|
|
34
|
+
defaultViewMode = _ref$defaultViewMode === void 0 ? 'read' : _ref$defaultViewMode,
|
|
35
|
+
onContentChange = _ref.onContentChange,
|
|
36
|
+
onExport = _ref.onExport;
|
|
29
37
|
// Log the imported SDK items to demonstrate usage
|
|
30
38
|
// console.log("Imported BlockSchema from SDK:", BlockSchema);
|
|
31
39
|
var _useState = useState(null),
|
|
@@ -48,7 +56,7 @@ function Structura(_ref) {
|
|
|
48
56
|
_useState0 = _slicedToArray(_useState9, 2),
|
|
49
57
|
fileUrl = _useState0[0],
|
|
50
58
|
setFileUrl = _useState0[1];
|
|
51
|
-
var _useState1 = useState(null),
|
|
59
|
+
var _useState1 = useState(initialJsonData || null),
|
|
52
60
|
_useState10 = _slicedToArray(_useState1, 2),
|
|
53
61
|
jsonData = _useState10[0],
|
|
54
62
|
setJsonData = _useState10[1];
|
|
@@ -93,20 +101,18 @@ function Structura(_ref) {
|
|
|
93
101
|
_useState30 = _slicedToArray(_useState29, 2),
|
|
94
102
|
isDraggingOver = _useState30[0],
|
|
95
103
|
setIsDraggingOver = _useState30[1]; //NOSONAR
|
|
96
|
-
//
|
|
104
|
+
// Sync initialJsonData prop with state when it changes
|
|
97
105
|
useEffect(function () {
|
|
98
|
-
var _a;
|
|
99
106
|
if (initialJsonData) {
|
|
100
|
-
console.log('[Structura] Loading initial JSON data from props');
|
|
101
107
|
setJsonData(initialJsonData);
|
|
102
|
-
var pageCount = ((_a = initialJsonData.children) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
103
|
-
setAllowedPages(Array.from({
|
|
104
|
-
length: pageCount
|
|
105
|
-
}, function (_, i) {
|
|
106
|
-
return i + 1;
|
|
107
|
-
}));
|
|
108
108
|
}
|
|
109
109
|
}, [initialJsonData]);
|
|
110
|
+
// Sync initialPdfPath prop with state when it changes
|
|
111
|
+
useEffect(function () {
|
|
112
|
+
if (initialPdfPath) {
|
|
113
|
+
setFileUrl(initialPdfPath);
|
|
114
|
+
}
|
|
115
|
+
}, [initialPdfPath]);
|
|
110
116
|
useEffect(function () {
|
|
111
117
|
var handleDragOver = function handleDragOver(e) {
|
|
112
118
|
e.preventDefault();
|
|
@@ -350,12 +356,10 @@ function Structura(_ref) {
|
|
|
350
356
|
// Add logging to the useEffect that watches isFileLoaded
|
|
351
357
|
useEffect(function () {
|
|
352
358
|
// console.log("!!! [Structura] isFileLoaded changed:", isFileLoaded);
|
|
353
|
-
// Skip
|
|
359
|
+
// Skip auto-generation if we already have JSON data from props
|
|
354
360
|
if (isFileLoaded && !initialJsonData) {
|
|
355
361
|
// console.log("!!! [Structura] Calling handleGenerateJSON due to isFileLoaded");
|
|
356
362
|
handleGenerateJSON();
|
|
357
|
-
} else if (isFileLoaded && initialJsonData) {
|
|
358
|
-
console.log('[Structura] Skipping API call - using cached JSON data');
|
|
359
363
|
}
|
|
360
364
|
}, [isFileLoaded, initialJsonData]);
|
|
361
365
|
// Handle removing the PDF and resetting state
|
|
@@ -391,7 +395,7 @@ function Structura(_ref) {
|
|
|
391
395
|
formData = new FormData();
|
|
392
396
|
formData.append("file", file);
|
|
393
397
|
// console.log("!!! [Structura] FormData:", formData);
|
|
394
|
-
if (
|
|
398
|
+
if (apiKey) {
|
|
395
399
|
_context2.n = 3;
|
|
396
400
|
break;
|
|
397
401
|
}
|
|
@@ -399,8 +403,8 @@ function Structura(_ref) {
|
|
|
399
403
|
case 3:
|
|
400
404
|
_context2.n = 4;
|
|
401
405
|
return POST(formData, {
|
|
402
|
-
apiKey:
|
|
403
|
-
baseUrl:
|
|
406
|
+
apiKey: apiKey,
|
|
407
|
+
baseUrl: baseUrl
|
|
404
408
|
});
|
|
405
409
|
case 4:
|
|
406
410
|
submitResponse = _context2.v;
|
|
@@ -431,8 +435,8 @@ function Structura(_ref) {
|
|
|
431
435
|
case 8:
|
|
432
436
|
_context2.n = 9;
|
|
433
437
|
return GET(requestId, {
|
|
434
|
-
apiKey:
|
|
435
|
-
baseUrl:
|
|
438
|
+
apiKey: apiKey,
|
|
439
|
+
baseUrl: baseUrl
|
|
436
440
|
});
|
|
437
441
|
case 9:
|
|
438
442
|
resultResponse = _context2.v;
|
|
@@ -600,28 +604,7 @@ function Structura(_ref) {
|
|
|
600
604
|
}
|
|
601
605
|
return jsxs("div", {
|
|
602
606
|
className: "h-screen max-h-screen flex flex-col bg-background text-foreground",
|
|
603
|
-
children: [jsx("
|
|
604
|
-
className: "border-b border-border bg-card p-4",
|
|
605
|
-
children: jsxs("div", {
|
|
606
|
-
className: "container mx-auto flex justify-between items-center",
|
|
607
|
-
children: [jsxs("div", {
|
|
608
|
-
className: "flex items-center space-x-2",
|
|
609
|
-
children: [jsx(LucideIcons.FileText, {
|
|
610
|
-
className: "h-6 w-6 text-primary"
|
|
611
|
-
}), jsx("h1", {
|
|
612
|
-
className: "text-2xl mt-2.5 font-bold",
|
|
613
|
-
children: "PLAYGROUND"
|
|
614
|
-
})]
|
|
615
|
-
}), jsx("div", {
|
|
616
|
-
className: "flex items-center gap-2",
|
|
617
|
-
children: jsx(Badge, {
|
|
618
|
-
variant: "outline",
|
|
619
|
-
className: "px-3 py-1 text-xs",
|
|
620
|
-
children: isFileLoaded ? "Document Loaded" : "No Document"
|
|
621
|
-
})
|
|
622
|
-
})]
|
|
623
|
-
})
|
|
624
|
-
}), jsx("div", {
|
|
607
|
+
children: [jsx("div", {
|
|
625
608
|
className: "md:hidden",
|
|
626
609
|
children: jsxs(Tabs, {
|
|
627
610
|
value: activeTab,
|
|
@@ -753,7 +736,14 @@ function Structura(_ref) {
|
|
|
753
736
|
selectedBboxId: selectedBboxId,
|
|
754
737
|
isLoading: isLoading,
|
|
755
738
|
onNodeClick: handleHtmlNodeClick,
|
|
756
|
-
|
|
739
|
+
editMode: editMode,
|
|
740
|
+
jsonMode: jsonMode,
|
|
741
|
+
mathRendering: mathRendering,
|
|
742
|
+
semanticTags: semanticTags,
|
|
743
|
+
headerFooterBadges: headerFooterBadges,
|
|
744
|
+
defaultViewMode: defaultViewMode,
|
|
745
|
+
onContentChange: onContentChange,
|
|
746
|
+
onExport: onExport
|
|
757
747
|
})
|
|
758
748
|
})
|
|
759
749
|
})]
|
|
@@ -766,22 +756,10 @@ function Structura(_ref) {
|
|
|
766
756
|
children: [jsx(Panel, {
|
|
767
757
|
minSize: 20,
|
|
768
758
|
defaultSize: 50,
|
|
769
|
-
children:
|
|
759
|
+
children: jsx(Card, {
|
|
770
760
|
className: "h-full border-0 rounded-none",
|
|
771
|
-
children:
|
|
772
|
-
className: "
|
|
773
|
-
children: jsxs(CardTitle, {
|
|
774
|
-
className: "text-base flex items-center gap-2",
|
|
775
|
-
children: [jsx(LucideIcons.FileText, {
|
|
776
|
-
className: "h-4 w-4"
|
|
777
|
-
}), "PDF Document", file && jsx(Badge, {
|
|
778
|
-
variant: "secondary",
|
|
779
|
-
className: "ml-2",
|
|
780
|
-
children: file.name
|
|
781
|
-
})]
|
|
782
|
-
})
|
|
783
|
-
}), jsx(CardContent, {
|
|
784
|
-
className: "p-0 flex-1 flex flex-col overflow-hidden",
|
|
761
|
+
children: jsx(CardContent, {
|
|
762
|
+
className: "p-0 flex-1 flex flex-col overflow-hidden h-full",
|
|
785
763
|
children: jsx(ScrollArea, {
|
|
786
764
|
className: "w-full h-[calc(100vh-220px)]",
|
|
787
765
|
children: fileUrl ? jsx(PdfDocumentViewer, {
|
|
@@ -876,25 +854,17 @@ function Structura(_ref) {
|
|
|
876
854
|
})
|
|
877
855
|
})
|
|
878
856
|
})
|
|
879
|
-
})
|
|
857
|
+
})
|
|
880
858
|
})
|
|
881
859
|
}), jsx(PanelResizeHandle, {
|
|
882
860
|
className: "w-1.5 bg-black hover:bg-primary/20 transition-colors cursor-col-resize"
|
|
883
861
|
}), jsx(Panel, {
|
|
884
862
|
minSize: 20,
|
|
885
863
|
defaultSize: 50,
|
|
886
|
-
children:
|
|
864
|
+
children: jsx(Card, {
|
|
887
865
|
className: "h-full border-0 rounded-none",
|
|
888
|
-
children:
|
|
889
|
-
className: "
|
|
890
|
-
children: jsxs(CardTitle, {
|
|
891
|
-
className: "text-base flex items-center gap-2",
|
|
892
|
-
children: [jsx(LucideIcons.FileText, {
|
|
893
|
-
className: "h-4 w-4"
|
|
894
|
-
}), "HTML Structure"]
|
|
895
|
-
})
|
|
896
|
-
}), jsx(CardContent, {
|
|
897
|
-
className: "p-0 h-[calc(100%-56px)] relative overflow-hidden",
|
|
866
|
+
children: jsx(CardContent, {
|
|
867
|
+
className: "p-0 h-full relative overflow-hidden",
|
|
898
868
|
children: jsx("div", {
|
|
899
869
|
className: "absolute inset-0",
|
|
900
870
|
children: jsonData ? jsx(HtmlViewer, {
|
|
@@ -902,7 +872,14 @@ function Structura(_ref) {
|
|
|
902
872
|
selectedBboxId: selectedBboxId,
|
|
903
873
|
isLoading: isLoading,
|
|
904
874
|
onNodeClick: handleHtmlNodeClick,
|
|
905
|
-
|
|
875
|
+
editMode: editMode,
|
|
876
|
+
jsonMode: jsonMode,
|
|
877
|
+
mathRendering: mathRendering,
|
|
878
|
+
semanticTags: semanticTags,
|
|
879
|
+
headerFooterBadges: headerFooterBadges,
|
|
880
|
+
defaultViewMode: defaultViewMode,
|
|
881
|
+
onContentChange: onContentChange,
|
|
882
|
+
onExport: onExport
|
|
906
883
|
}) : jsx("div", {
|
|
907
884
|
className: "flex flex-col items-center justify-center h-full p-8 text-center",
|
|
908
885
|
children: jsxs("div", {
|
|
@@ -919,7 +896,7 @@ function Structura(_ref) {
|
|
|
919
896
|
})
|
|
920
897
|
})
|
|
921
898
|
})
|
|
922
|
-
})
|
|
899
|
+
})
|
|
923
900
|
})
|
|
924
901
|
})]
|
|
925
902
|
})
|