@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.
Files changed (49) hide show
  1. package/README.md +72 -323
  2. package/dist/cjs/EditableContent.js +46 -18
  3. package/dist/cjs/HtmlViewer.js +238 -85
  4. package/dist/cjs/MathRenderer.js +88 -0
  5. package/dist/cjs/PdfDocumentViewer.js +1 -1
  6. package/dist/cjs/SemanticTagParser.js +189 -0
  7. package/dist/cjs/SemanticTagRenderer.js +135 -0
  8. package/dist/cjs/Structura.js +49 -76
  9. package/dist/cjs/Table.js +75 -8
  10. package/dist/cjs/TableCell.js +34 -10
  11. package/dist/cjs/index.js +12 -0
  12. package/dist/cjs/node_modules/react-icons/fa/index.esm.js +6 -0
  13. package/dist/cjs/styles.css +2 -4
  14. package/dist/cjs/styles.css.map +1 -1
  15. package/dist/esm/EditableContent.js +51 -19
  16. package/dist/esm/HtmlViewer.js +287 -103
  17. package/dist/esm/MathRenderer.js +85 -0
  18. package/dist/esm/PdfDocumentViewer.js +1 -1
  19. package/dist/esm/SemanticTagParser.js +187 -0
  20. package/dist/esm/SemanticTagRenderer.js +140 -0
  21. package/dist/esm/Structura.js +57 -80
  22. package/dist/esm/Table.js +85 -8
  23. package/dist/esm/TableCell.js +34 -6
  24. package/dist/esm/index.js +3 -0
  25. package/dist/esm/node_modules/react-icons/fa/index.esm.js +5 -1
  26. package/dist/esm/styles.css +2 -4
  27. package/dist/esm/styles.css.map +1 -1
  28. package/dist/esm/types/DocumentOutline.d.ts +7 -0
  29. package/dist/esm/types/EditableContent.d.ts +8 -1
  30. package/dist/esm/types/HtmlViewer.d.ts +9 -2
  31. package/dist/esm/types/MathRenderer.d.ts +25 -0
  32. package/dist/esm/types/SemanticTagParser.d.ts +33 -0
  33. package/dist/esm/types/SemanticTagRenderer.d.ts +17 -0
  34. package/dist/esm/types/Structura.d.ts +13 -8
  35. package/dist/esm/types/Table.d.ts +4 -1
  36. package/dist/esm/types/TableCell.d.ts +7 -1
  37. package/dist/esm/types/helpers/index.d.ts +0 -1
  38. package/dist/esm/types/index.d.ts +3 -0
  39. package/dist/esm/types/test-app/src/App.d.ts +1 -2
  40. package/dist/index.d.ts +90 -10
  41. package/package.json +9 -16
  42. package/PRODUCTION_ARCHITECTURE.md +0 -511
  43. package/SAVE_FUNCTIONALITY_COMPLETE.md +0 -448
  44. package/dist/cjs/ui/badge.js +0 -34
  45. package/dist/esm/types/helpers/jsonToHtml.d.ts +0 -40
  46. package/dist/esm/ui/badge.js +0 -31
  47. package/server/README.md +0 -203
  48. package/server/db.js +0 -142
  49. package/server/server.js +0 -165
@@ -0,0 +1,189 @@
1
+ 'use strict';
2
+
3
+ // Semantic Tag Parser for SOP/Batch Record domain tags
4
+ // Supports: MeasurementTag, HiddenMeasurementTag, ValueTag, DateTimeTag, FileTag, ImageTag
5
+ // Regular expression patterns for tag detection
6
+ // Standard tag: [[value][type:TYPE][attr:value]...]
7
+ // Hidden tag: {[value][type:TYPE][attr:value]...]}
8
+ const STANDARD_TAG_PATTERN = /\[\[([^\]]+)\](\[([^\]]+)\])*\]/g;
9
+ const HIDDEN_TAG_PATTERN = /\{\[([^\]]+)\](\[([^\]]+)\])*\]\}/g;
10
+ // Parse a single tag's attribute string like "[type:MEASUREMENT][uom:mL/min][id:abc-123]"
11
+ function parseTagAttributes(attributeStr) {
12
+ const attributes = {};
13
+ let type = 'VALUE'; // Default type
14
+ // Match all [key:value] pairs
15
+ const attrPattern = /\[([^:\]]+):([^\]]+)\]/g;
16
+ let match;
17
+ while ((match = attrPattern.exec(attributeStr)) !== null) {
18
+ const key = match[1].toLowerCase();
19
+ const value = match[2];
20
+ switch (key) {
21
+ case 'type':
22
+ type = value.toUpperCase();
23
+ break;
24
+ case 'uom':
25
+ attributes.uom = value;
26
+ break;
27
+ case 'id':
28
+ attributes.id = value;
29
+ break;
30
+ case 'format':
31
+ attributes.format = value;
32
+ break;
33
+ case 'filter':
34
+ attributes.filter = value;
35
+ break;
36
+ }
37
+ }
38
+ return {
39
+ type,
40
+ attributes
41
+ };
42
+ }
43
+ // Parse a single tag match
44
+ function parseTag(match, isHidden) {
45
+ const rawMatch = match[0];
46
+ const startIndex = match.index;
47
+ const endIndex = startIndex + rawMatch.length;
48
+ // Extract the value (first bracket content) and attributes (remaining brackets)
49
+ let innerContent;
50
+ if (isHidden) {
51
+ // Remove {[ and ]} wrapper
52
+ innerContent = rawMatch.slice(2, -2);
53
+ } else {
54
+ // Remove [[ and ]] wrapper (but there might be more brackets for attributes)
55
+ innerContent = rawMatch.slice(2, -1);
56
+ }
57
+ // Split by ][ to get value and attributes
58
+ const parts = innerContent.split('][');
59
+ const value = parts[0];
60
+ const attributeStr = parts.length > 1 ? '[' + parts.slice(1).join('][') + ']' : '';
61
+ const {
62
+ type,
63
+ attributes
64
+ } = parseTagAttributes(attributeStr);
65
+ // Adjust type for hidden tags
66
+ const finalType = isHidden ? 'HIDDEN_MEASUREMENT' : type;
67
+ return {
68
+ type: finalType,
69
+ value,
70
+ rawMatch,
71
+ startIndex,
72
+ endIndex,
73
+ attributes,
74
+ isHidden
75
+ };
76
+ }
77
+ // Main parsing function
78
+ function parseSemanticTags(text) {
79
+ const tags = [];
80
+ // Find all standard tags
81
+ let match;
82
+ const standardPattern = new RegExp(STANDARD_TAG_PATTERN.source, 'g');
83
+ while ((match = standardPattern.exec(text)) !== null) {
84
+ tags.push(parseTag(match, false));
85
+ }
86
+ // Find all hidden tags
87
+ const hiddenPattern = new RegExp(HIDDEN_TAG_PATTERN.source, 'g');
88
+ while ((match = hiddenPattern.exec(text)) !== null) {
89
+ tags.push(parseTag(match, true));
90
+ }
91
+ // Sort tags by start index
92
+ tags.sort((a, b) => a.startIndex - b.startIndex);
93
+ // Build segments
94
+ const segments = [];
95
+ let currentIndex = 0;
96
+ for (const tag of tags) {
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
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,
124
+ 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
+ exports.getTagTypeInfo = getTagTypeInfo;
188
+ exports.hasSemanticTags = hasSemanticTags;
189
+ exports.parseSemanticTags = parseSemanticTags;
@@ -0,0 +1,135 @@
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
+ var SemanticTagParser = require('./SemanticTagParser.js');
8
+
9
+ // Individual tag badge component
10
+ function TagBadge({
11
+ tag,
12
+ showTooltip = true,
13
+ onClick
14
+ }) {
15
+ const [isHovered, setIsHovered] = React.useState(false);
16
+ const typeInfo = SemanticTagParser.getTagTypeInfo(tag.type);
17
+ return jsxRuntime.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
19
+ ${typeInfo.bgColor} ${typeInfo.color}
20
+ ${onClick ? 'cursor-pointer hover:shadow-md' : ''}
21
+ ${isHovered ? 'ring-2 ring-offset-1 ring-blue-400' : ''}`,
22
+ onMouseEnter: () => setIsHovered(true),
23
+ onMouseLeave: () => setIsHovered(false),
24
+ onClick: onClick,
25
+ children: [jsxRuntime.jsx("span", {
26
+ className: "text-[10px]",
27
+ children: typeInfo.icon
28
+ }), jsxRuntime.jsx("span", {
29
+ children: tag.value
30
+ }), tag.attributes.uom && jsxRuntime.jsx("span", {
31
+ className: "text-[10px] opacity-75 ml-0.5",
32
+ children: tag.attributes.uom
33
+ }), showTooltip && isHovered && jsxRuntime.jsx("div", {
34
+ className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-50 pointer-events-none",
35
+ children: jsxRuntime.jsxs("div", {
36
+ className: "bg-gray-900 text-white text-xs rounded-lg px-3 py-2 shadow-lg whitespace-nowrap",
37
+ children: [jsxRuntime.jsxs("div", {
38
+ className: "font-semibold mb-1",
39
+ children: [typeInfo.label, " Tag"]
40
+ }), jsxRuntime.jsxs("div", {
41
+ className: "space-y-0.5 text-gray-300",
42
+ children: [jsxRuntime.jsxs("div", {
43
+ children: ["Value: ", jsxRuntime.jsx("span", {
44
+ className: "text-white",
45
+ children: tag.value
46
+ })]
47
+ }), tag.attributes.uom && jsxRuntime.jsxs("div", {
48
+ children: ["Unit: ", jsxRuntime.jsx("span", {
49
+ className: "text-white",
50
+ children: tag.attributes.uom
51
+ })]
52
+ }), tag.attributes.id && jsxRuntime.jsxs("div", {
53
+ className: "text-[10px] text-gray-400 truncate max-w-[200px]",
54
+ children: ["ID: ", tag.attributes.id]
55
+ }), tag.attributes.format && jsxRuntime.jsxs("div", {
56
+ children: ["Format: ", jsxRuntime.jsx("span", {
57
+ className: "text-white",
58
+ children: tag.attributes.format
59
+ })]
60
+ })]
61
+ }), jsxRuntime.jsx("div", {
62
+ className: "absolute top-full left-1/2 -translate-x-1/2 -mt-px",
63
+ children: jsxRuntime.jsx("div", {
64
+ className: "border-4 border-transparent border-t-gray-900"
65
+ })
66
+ })]
67
+ })
68
+ })]
69
+ });
70
+ }
71
+ // Main renderer component
72
+ function SemanticTagRenderer({
73
+ content,
74
+ className = '',
75
+ showTooltips = true,
76
+ onTagClick
77
+ }) {
78
+ // If no semantic tags, just return the content as-is
79
+ if (!SemanticTagParser.hasSemanticTags(content)) {
80
+ return jsxRuntime.jsx("span", {
81
+ className: className,
82
+ dangerouslySetInnerHTML: {
83
+ __html: content
84
+ }
85
+ });
86
+ }
87
+ const parsed = SemanticTagParser.parseSemanticTags(content);
88
+ return jsxRuntime.jsx("span", {
89
+ className: className,
90
+ children: parsed.segments.map((segment, index) => {
91
+ if (segment.type === 'text') {
92
+ // Render plain text (may contain HTML)
93
+ return jsxRuntime.jsx("span", {
94
+ dangerouslySetInnerHTML: {
95
+ __html: segment.content
96
+ }
97
+ }, index);
98
+ } else if (segment.type === 'tag' && segment.tag) {
99
+ // Render semantic tag badge
100
+ return jsxRuntime.jsx(TagBadge, {
101
+ tag: segment.tag,
102
+ showTooltip: showTooltips,
103
+ onClick: onTagClick ? () => onTagClick(segment.tag) : undefined
104
+ }, index);
105
+ }
106
+ return null;
107
+ })
108
+ });
109
+ }
110
+ function SmartContent({
111
+ content,
112
+ className = '',
113
+ enableSemanticTags = true,
114
+ showTooltips = true,
115
+ onTagClick
116
+ }) {
117
+ if (enableSemanticTags && SemanticTagParser.hasSemanticTags(content)) {
118
+ return jsxRuntime.jsx(SemanticTagRenderer, {
119
+ content: content,
120
+ className: className,
121
+ showTooltips: showTooltips,
122
+ onTagClick: onTagClick
123
+ });
124
+ }
125
+ // Regular content without semantic tags
126
+ return jsxRuntime.jsx("span", {
127
+ className: className,
128
+ dangerouslySetInnerHTML: {
129
+ __html: content
130
+ }
131
+ });
132
+ }
133
+
134
+ exports.SmartContent = SmartContent;
135
+ exports.default = SemanticTagRenderer;
@@ -12,7 +12,6 @@ var PdfDocumentViewer = require('./PdfDocumentViewer.js');
12
12
  var HtmlViewer = require('./HtmlViewer.js');
13
13
  var preprocessData = require('./helpers/preprocessData.js');
14
14
  var reactResizablePanels = require('react-resizable-panels');
15
- var badge = require('./ui/badge.js');
16
15
  var progress = require('./ui/progress.js');
17
16
  var scrollArea = require('./ui/scroll-area.js');
18
17
  var route = require('./route.js');
@@ -39,16 +38,19 @@ var LucideIcons__namespace = /*#__PURE__*/_interopNamespaceDefault(LucideIcons);
39
38
  // Remove component aliases and use direct imports
40
39
  // This will preserve the propser types
41
40
  function Structura({
41
+ apiKey,
42
+ baseUrl,
42
43
  initialPdfPath,
43
44
  initialJsonData,
44
- props
45
+ editMode = true,
46
+ jsonMode = true,
47
+ mathRendering = true,
48
+ semanticTags = true,
49
+ headerFooterBadges = true,
50
+ defaultViewMode = 'read',
51
+ onContentChange,
52
+ onExport
45
53
  }) {
46
- // Log the API key (for development only - remove in production)
47
- // useEffect(() => {
48
- // if (props?.APIKey) {
49
- // console.log("API Key provided:", props.APIKey);
50
- // }
51
- // }, [props]);
52
54
  // Log the imported SDK items to demonstrate usage
53
55
  // console.log("Imported BlockSchema from SDK:", BlockSchema);
54
56
  const [numPages, setNumPages] = React.useState(null);
@@ -56,7 +58,7 @@ function Structura({
56
58
  const [selectedField, setSelectedField] = React.useState(null);
57
59
  const [file, setFile] = React.useState(null);
58
60
  const [fileUrl, setFileUrl] = React.useState(initialPdfPath || null);
59
- const [jsonData, setJsonData] = React.useState(null);
61
+ const [jsonData, setJsonData] = React.useState(initialJsonData || null);
60
62
  const [allowedPages, setAllowedPages] = React.useState(null);
61
63
  const pdfWrapperRef = React.useRef(null);
62
64
  const [flattenedFields, setFlattenedFields] = React.useState([]);
@@ -68,18 +70,18 @@ function Structura({
68
70
  const [activeTab, setActiveTab] = React.useState("pdf");
69
71
  const [backendStatus, setBackendStatus] = React.useState('checking');
70
72
  const [isDraggingOver, setIsDraggingOver] = React.useState(false); //NOSONAR
71
- // Load initial JSON data if provided (for faster iteration without API calls)
73
+ // Sync initialJsonData prop with state when it changes
72
74
  React.useEffect(() => {
73
- var _a;
74
75
  if (initialJsonData) {
75
- console.log('[Structura] Loading initial JSON data from props');
76
76
  setJsonData(initialJsonData);
77
- const pageCount = ((_a = initialJsonData.children) === null || _a === void 0 ? void 0 : _a.length) || 0;
78
- setAllowedPages(Array.from({
79
- length: pageCount
80
- }, (_, i) => i + 1));
81
77
  }
82
78
  }, [initialJsonData]);
79
+ // Sync initialPdfPath prop with state when it changes
80
+ React.useEffect(() => {
81
+ if (initialPdfPath) {
82
+ setFileUrl(initialPdfPath);
83
+ }
84
+ }, [initialPdfPath]);
83
85
  React.useEffect(() => {
84
86
  const handleDragOver = e => {
85
87
  e.preventDefault();
@@ -273,12 +275,10 @@ function Structura({
273
275
  // Add logging to the useEffect that watches isFileLoaded
274
276
  React.useEffect(() => {
275
277
  // console.log("!!! [Structura] isFileLoaded changed:", isFileLoaded);
276
- // Skip API call if we already have initialJsonData (cached mode)
278
+ // Skip auto-generation if we already have JSON data from props
277
279
  if (isFileLoaded && !initialJsonData) {
278
280
  // console.log("!!! [Structura] Calling handleGenerateJSON due to isFileLoaded");
279
281
  handleGenerateJSON();
280
- } else if (isFileLoaded && initialJsonData) {
281
- console.log('[Structura] Skipping API call - using cached JSON data');
282
282
  }
283
283
  }, [isFileLoaded, initialJsonData]);
284
284
  // Handle removing the PDF and resetting state
@@ -304,12 +304,12 @@ function Structura({
304
304
  const formData = new FormData();
305
305
  formData.append("file", file);
306
306
  // console.log("!!! [Structura] FormData:", formData);
307
- if (!(props === null || props === void 0 ? void 0 : props.APIKey)) {
307
+ if (!apiKey) {
308
308
  throw new Error("API key is required but not provided");
309
309
  }
310
310
  const submitResponse = await route.POST(formData, {
311
- apiKey: props.APIKey,
312
- baseUrl: props.baseUrl
311
+ apiKey: apiKey,
312
+ baseUrl: baseUrl
313
313
  });
314
314
  console.log("API response status:", submitResponse.status);
315
315
  if (submitResponse.status !== 200) {
@@ -330,8 +330,8 @@ function Structura({
330
330
  let resultData = null;
331
331
  while (true) {
332
332
  const resultResponse = await route.GET(requestId, {
333
- apiKey: props.APIKey,
334
- baseUrl: props.baseUrl
333
+ apiKey: apiKey,
334
+ baseUrl: baseUrl
335
335
  });
336
336
  if (resultResponse.data.status === "completed") {
337
337
  // Store the response data
@@ -455,28 +455,7 @@ function Structura({
455
455
  }
456
456
  return jsxRuntime.jsxs("div", {
457
457
  className: "h-screen max-h-screen flex flex-col bg-background text-foreground",
458
- children: [jsxRuntime.jsx("header", {
459
- className: "border-b border-border bg-card p-4",
460
- children: jsxRuntime.jsxs("div", {
461
- className: "container mx-auto flex justify-between items-center",
462
- children: [jsxRuntime.jsxs("div", {
463
- className: "flex items-center space-x-2",
464
- children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
465
- className: "h-6 w-6 text-primary"
466
- }), jsxRuntime.jsx("h1", {
467
- className: "text-2xl mt-2.5 font-bold",
468
- children: "PLAYGROUND"
469
- })]
470
- }), jsxRuntime.jsx("div", {
471
- className: "flex items-center gap-2",
472
- children: jsxRuntime.jsx(badge.Badge, {
473
- variant: "outline",
474
- className: "px-3 py-1 text-xs",
475
- children: isFileLoaded ? "Document Loaded" : "No Document"
476
- })
477
- })]
478
- })
479
- }), jsxRuntime.jsx("div", {
458
+ children: [jsxRuntime.jsx("div", {
480
459
  className: "md:hidden",
481
460
  children: jsxRuntime.jsxs(tabs.Tabs, {
482
461
  value: activeTab,
@@ -608,7 +587,14 @@ function Structura({
608
587
  selectedBboxId: selectedBboxId,
609
588
  isLoading: isLoading,
610
589
  onNodeClick: handleHtmlNodeClick,
611
- onSave: props.onSave
590
+ editMode: editMode,
591
+ jsonMode: jsonMode,
592
+ mathRendering: mathRendering,
593
+ semanticTags: semanticTags,
594
+ headerFooterBadges: headerFooterBadges,
595
+ defaultViewMode: defaultViewMode,
596
+ onContentChange: onContentChange,
597
+ onExport: onExport
612
598
  })
613
599
  })
614
600
  })]
@@ -621,22 +607,10 @@ function Structura({
621
607
  children: [jsxRuntime.jsx(reactResizablePanels.Panel, {
622
608
  minSize: 20,
623
609
  defaultSize: 50,
624
- children: jsxRuntime.jsxs(card.Card, {
610
+ children: jsxRuntime.jsx(card.Card, {
625
611
  className: "h-full border-0 rounded-none",
626
- children: [jsxRuntime.jsx(card.CardHeader, {
627
- className: "py-3 px-4 border-b bg-muted/30",
628
- children: jsxRuntime.jsxs(card.CardTitle, {
629
- className: "text-base flex items-center gap-2",
630
- children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
631
- className: "h-4 w-4"
632
- }), "PDF Document", file && jsxRuntime.jsx(badge.Badge, {
633
- variant: "secondary",
634
- className: "ml-2",
635
- children: file.name
636
- })]
637
- })
638
- }), jsxRuntime.jsx(card.CardContent, {
639
- className: "p-0 flex-1 flex flex-col overflow-hidden",
612
+ children: jsxRuntime.jsx(card.CardContent, {
613
+ className: "p-0 flex-1 flex flex-col overflow-hidden h-full",
640
614
  children: jsxRuntime.jsx(scrollArea.ScrollArea, {
641
615
  className: "w-full h-[calc(100vh-220px)]",
642
616
  children: fileUrl ? jsxRuntime.jsx(PdfDocumentViewer.default, {
@@ -731,25 +705,17 @@ function Structura({
731
705
  })
732
706
  })
733
707
  })
734
- })]
708
+ })
735
709
  })
736
710
  }), jsxRuntime.jsx(reactResizablePanels.PanelResizeHandle, {
737
711
  className: "w-1.5 bg-black hover:bg-primary/20 transition-colors cursor-col-resize"
738
712
  }), jsxRuntime.jsx(reactResizablePanels.Panel, {
739
713
  minSize: 20,
740
714
  defaultSize: 50,
741
- children: jsxRuntime.jsxs(card.Card, {
715
+ children: jsxRuntime.jsx(card.Card, {
742
716
  className: "h-full border-0 rounded-none",
743
- children: [jsxRuntime.jsx(card.CardHeader, {
744
- className: "py-3 px-4 border-b bg-muted/30",
745
- children: jsxRuntime.jsxs(card.CardTitle, {
746
- className: "text-base flex items-center gap-2",
747
- children: [jsxRuntime.jsx(LucideIcons__namespace.FileText, {
748
- className: "h-4 w-4"
749
- }), "HTML Structure"]
750
- })
751
- }), jsxRuntime.jsx(card.CardContent, {
752
- className: "p-0 h-[calc(100%-56px)] relative overflow-hidden",
717
+ children: jsxRuntime.jsx(card.CardContent, {
718
+ className: "p-0 h-full relative overflow-hidden",
753
719
  children: jsxRuntime.jsx("div", {
754
720
  className: "absolute inset-0",
755
721
  children: jsonData ? jsxRuntime.jsx(HtmlViewer.default, {
@@ -757,7 +723,14 @@ function Structura({
757
723
  selectedBboxId: selectedBboxId,
758
724
  isLoading: isLoading,
759
725
  onNodeClick: handleHtmlNodeClick,
760
- onSave: props.onSave
726
+ editMode: editMode,
727
+ jsonMode: jsonMode,
728
+ mathRendering: mathRendering,
729
+ semanticTags: semanticTags,
730
+ headerFooterBadges: headerFooterBadges,
731
+ defaultViewMode: defaultViewMode,
732
+ onContentChange: onContentChange,
733
+ onExport: onExport
761
734
  }) : jsxRuntime.jsx("div", {
762
735
  className: "flex flex-col items-center justify-center h-full p-8 text-center",
763
736
  children: jsxRuntime.jsxs("div", {
@@ -774,7 +747,7 @@ function Structura({
774
747
  })
775
748
  })
776
749
  })
777
- })]
750
+ })
778
751
  })
779
752
  })]
780
753
  })