@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
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tfw.in/structura-lib
|
|
2
2
|
|
|
3
|
-
A React component library for viewing
|
|
3
|
+
A React component library for PDF document viewing with structured data extraction and rendering.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- **PDF & JSON Side-by-Side Viewing** - View original PDF alongside extracted structured content
|
|
8
|
+
- **Edit Mode** - Inline editing of extracted content
|
|
9
|
+
- **Math Rendering** - LaTeX math expressions rendered via KaTeX (`$...$` inline, `$$...$$` display)
|
|
10
|
+
- **Semantic Tags** - Visual highlighting for corrections, additions, and deletions
|
|
11
|
+
- **Header/Footer Detection** - Automatic badges for header and footer content
|
|
12
|
+
- **Table Support** - Rich table rendering with cell-level editing
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
15
15
|
|
|
@@ -17,363 +17,112 @@ A React component library for viewing and editing structured documents with PDF
|
|
|
17
17
|
npm install @tfw.in/structura-lib
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Usage
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```tsx
|
|
22
|
+
```jsx
|
|
25
23
|
import { Structura } from '@tfw.in/structura-lib';
|
|
26
24
|
import '@tfw.in/structura-lib/dist/esm/styles.css';
|
|
27
25
|
|
|
28
26
|
function App() {
|
|
29
27
|
return (
|
|
30
28
|
<Structura
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
props={{
|
|
34
|
-
APIKey: "your-api-key",
|
|
35
|
-
onSave: (editedData) => {
|
|
36
|
-
console.log('Document saved:', editedData);
|
|
37
|
-
}
|
|
38
|
-
}}
|
|
29
|
+
apiKey="your-api-key"
|
|
30
|
+
baseUrl="https://api.example.com"
|
|
39
31
|
/>
|
|
40
32
|
);
|
|
41
33
|
}
|
|
42
34
|
```
|
|
43
35
|
|
|
44
|
-
|
|
36
|
+
## Props
|
|
45
37
|
|
|
46
|
-
|
|
38
|
+
| Prop | Type | Default | Description |
|
|
39
|
+
|------|------|---------|-------------|
|
|
40
|
+
| `apiKey` | `string` | **required** | API key for authentication |
|
|
41
|
+
| `baseUrl` | `string` | `undefined` | Optional API base URL |
|
|
42
|
+
| `initialPdfPath` | `string \| null` | `null` | Initial PDF file path to load |
|
|
43
|
+
| `initialJsonData` | `any` | `null` | Initial JSON data to display |
|
|
44
|
+
| `editMode` | `boolean` | `true` | Enable/disable edit mode toggle |
|
|
45
|
+
| `jsonMode` | `boolean` | `true` | Enable/disable JSON view mode toggle |
|
|
46
|
+
| `mathRendering` | `boolean` | `true` | Enable LaTeX math rendering |
|
|
47
|
+
| `semanticTags` | `boolean` | `true` | Enable/disable semantic tags toggle |
|
|
48
|
+
| `headerFooterBadges` | `boolean` | `true` | Show header/footer badges |
|
|
49
|
+
| `defaultViewMode` | `'read' \| 'edit' \| 'json'` | `'read'` | Initial view mode |
|
|
50
|
+
| `onContentChange` | `function` | `undefined` | Callback when content is edited |
|
|
51
|
+
| `onExport` | `function` | `undefined` | Callback when data is exported |
|
|
52
|
+
|
|
53
|
+
## Full Example
|
|
54
|
+
|
|
55
|
+
```jsx
|
|
47
56
|
import { Structura } from '@tfw.in/structura-lib';
|
|
48
57
|
import '@tfw.in/structura-lib/dist/esm/styles.css';
|
|
49
58
|
|
|
50
59
|
function App() {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
headers: { 'Content-Type': 'application/json' },
|
|
57
|
-
body: JSON.stringify({
|
|
58
|
-
pdfName: 'document.pdf',
|
|
59
|
-
editedJson: editedData,
|
|
60
|
-
originalJson: jsonData // Only on first save
|
|
61
|
-
})
|
|
62
|
-
});
|
|
60
|
+
const handleContentChange = (blockId, oldContent, newContent) => {
|
|
61
|
+
console.log(`Block ${blockId} changed`);
|
|
62
|
+
console.log('Old:', oldContent);
|
|
63
|
+
console.log('New:', newContent);
|
|
64
|
+
};
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
console.log('
|
|
66
|
+
const handleExport = (data) => {
|
|
67
|
+
console.log('Exported data:', data);
|
|
68
|
+
// Save to your backend, etc.
|
|
66
69
|
};
|
|
67
70
|
|
|
68
71
|
return (
|
|
69
72
|
<Structura
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
73
|
+
apiKey="your-api-key"
|
|
74
|
+
baseUrl="https://api.example.com"
|
|
75
|
+
editMode={true}
|
|
76
|
+
jsonMode={true}
|
|
77
|
+
mathRendering={true}
|
|
78
|
+
semanticTags={true}
|
|
79
|
+
headerFooterBadges={true}
|
|
80
|
+
defaultViewMode="read"
|
|
81
|
+
onContentChange={handleContentChange}
|
|
82
|
+
onExport={handleExport}
|
|
76
83
|
/>
|
|
77
84
|
);
|
|
78
85
|
}
|
|
79
86
|
```
|
|
80
87
|
|
|
81
|
-
##
|
|
82
|
-
|
|
83
|
-
### `Structura` Component
|
|
88
|
+
## Math Rendering
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
|------|------|----------|-------------|
|
|
87
|
-
| `initialPdfPath` | `string \| null` | No | URL or path to PDF file |
|
|
88
|
-
| `initialJsonData` | `any \| null` | No | Pre-loaded JSON data (bypasses API call) |
|
|
89
|
-
| `props.APIKey` | `string` | Yes | Structura API key for processing |
|
|
90
|
-
| `props.baseUrl` | `string` | No | Custom API base URL |
|
|
91
|
-
| `props.onSave` | `(data: any) => void \| Promise<void>` | No | Callback when user saves edits |
|
|
92
|
-
|
|
93
|
-
## Backend Server (Optional)
|
|
94
|
-
|
|
95
|
-
The library includes an Express server for persistent storage.
|
|
96
|
-
|
|
97
|
-
### Start the Server
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
cd node_modules/@tfw.in/structura-lib
|
|
101
|
-
npm run server
|
|
102
|
-
```
|
|
90
|
+
The library automatically renders LaTeX math expressions in content:
|
|
103
91
|
|
|
104
|
-
|
|
92
|
+
- Inline math: `$x^2 + y^2 = z^2$`
|
|
93
|
+
- Display math: `$$\sum_{i=1}^{n} x_i$$`
|
|
105
94
|
|
|
106
|
-
|
|
95
|
+
You can also use the math utilities directly:
|
|
107
96
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
curl -X POST http://localhost:3002/api/save \
|
|
113
|
-
-H "Content-Type: application/json" \
|
|
114
|
-
-d '{
|
|
115
|
-
"pdfName": "document.pdf",
|
|
116
|
-
"editedJson": {...},
|
|
117
|
-
"originalJson": {...}
|
|
118
|
-
}'
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
#### GET /api/load/:pdfName
|
|
122
|
-
Load document with latest edit.
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
curl http://localhost:3002/api/load/document.pdf
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
#### GET /api/history/:pdfName
|
|
129
|
-
Get full edit history.
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
curl http://localhost:3002/api/history/document.pdf
|
|
133
|
-
```
|
|
97
|
+
```jsx
|
|
98
|
+
import { MathContent, renderMathInHtml, containsMath } from '@tfw.in/structura-lib';
|
|
134
99
|
|
|
135
|
-
|
|
100
|
+
// React component
|
|
101
|
+
<MathContent html="The formula is $E = mc^2$" />
|
|
136
102
|
|
|
137
|
-
|
|
103
|
+
// Utility function
|
|
104
|
+
const rendered = renderMathInHtml("Price is $20$ dollars");
|
|
138
105
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// Try database first
|
|
144
|
-
fetch(`http://localhost:3002/api/load/${pdfName}`)
|
|
145
|
-
.then(res => res.json())
|
|
146
|
-
.then(result => {
|
|
147
|
-
setJsonData(result.document.currentJson);
|
|
148
|
-
})
|
|
149
|
-
.catch(() => {
|
|
150
|
-
// Fallback to file
|
|
151
|
-
fetch('/data.json')
|
|
152
|
-
.then(res => res.json())
|
|
153
|
-
.then(data => setJsonData(data));
|
|
154
|
-
});
|
|
155
|
-
}, []);
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Pattern 2: Auto-Save on Edit
|
|
159
|
-
|
|
160
|
-
```tsx
|
|
161
|
-
const handleSave = async (editedData) => {
|
|
162
|
-
await fetch('http://localhost:3002/api/save', {
|
|
163
|
-
method: 'POST',
|
|
164
|
-
headers: { 'Content-Type': 'application/json' },
|
|
165
|
-
body: JSON.stringify({
|
|
166
|
-
pdfName: pdfUrl.split('/').pop(),
|
|
167
|
-
editedJson: editedData
|
|
168
|
-
})
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Reload from database to verify
|
|
172
|
-
const response = await fetch(`http://localhost:3002/api/load/${pdfName}`);
|
|
173
|
-
const result = await response.json();
|
|
174
|
-
setJsonData(result.document.currentJson);
|
|
175
|
-
};
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Pattern 3: URL Parameters
|
|
179
|
-
|
|
180
|
-
```tsx
|
|
181
|
-
// Load from URL: ?pdf=/doc.pdf&json=/data.json
|
|
182
|
-
useEffect(() => {
|
|
183
|
-
const params = new URLSearchParams(window.location.search);
|
|
184
|
-
const pdf = params.get('pdf');
|
|
185
|
-
const json = params.get('json');
|
|
186
|
-
|
|
187
|
-
if (pdf && json) {
|
|
188
|
-
setPdfUrl(pdf);
|
|
189
|
-
fetch(json)
|
|
190
|
-
.then(res => res.json())
|
|
191
|
-
.then(data => setJsonData(data));
|
|
192
|
-
}
|
|
193
|
-
}, []);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Features
|
|
197
|
-
|
|
198
|
-
### Inline Editing
|
|
199
|
-
|
|
200
|
-
Double-click any text to edit:
|
|
201
|
-
- Edits are tracked automatically
|
|
202
|
-
- Green **Save** button appears when changes are made
|
|
203
|
-
- Yellow highlight indicates edited content
|
|
204
|
-
|
|
205
|
-
### Version History
|
|
206
|
-
|
|
207
|
-
Every save creates a new version:
|
|
208
|
-
- Full edit history preserved
|
|
209
|
-
- Timestamps for each edit
|
|
210
|
-
- Can restore any previous version
|
|
211
|
-
|
|
212
|
-
### Bidirectional Mapping
|
|
213
|
-
|
|
214
|
-
Click elements to highlight corresponding content:
|
|
215
|
-
- PDF → HTML viewer
|
|
216
|
-
- HTML viewer → PDF location
|
|
217
|
-
- Smooth scrolling and highlighting
|
|
218
|
-
|
|
219
|
-
## Development
|
|
220
|
-
|
|
221
|
-
### Build the Library
|
|
222
|
-
|
|
223
|
-
```bash
|
|
224
|
-
npm run build
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Run Test App
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
cd test-app
|
|
231
|
-
npm install
|
|
232
|
-
npm run dev
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Open: `http://localhost:5175`
|
|
236
|
-
|
|
237
|
-
### Run with Backend
|
|
238
|
-
|
|
239
|
-
Terminal 1:
|
|
240
|
-
```bash
|
|
241
|
-
npm run server
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Terminal 2:
|
|
245
|
-
```bash
|
|
246
|
-
cd test-app
|
|
247
|
-
npm run dev
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
## Database Schema
|
|
251
|
-
|
|
252
|
-
### documents table
|
|
253
|
-
```sql
|
|
254
|
-
CREATE TABLE documents (
|
|
255
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
256
|
-
pdf_name TEXT NOT NULL,
|
|
257
|
-
original_json TEXT NOT NULL,
|
|
258
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
259
|
-
);
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### edits table
|
|
263
|
-
```sql
|
|
264
|
-
CREATE TABLE edits (
|
|
265
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
266
|
-
document_id INTEGER NOT NULL,
|
|
267
|
-
edited_json TEXT NOT NULL,
|
|
268
|
-
edit_summary TEXT,
|
|
269
|
-
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
270
|
-
FOREIGN KEY (document_id) REFERENCES documents(id)
|
|
271
|
-
);
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## Architecture
|
|
275
|
-
|
|
276
|
-
```
|
|
277
|
-
┌──────────────────┐
|
|
278
|
-
│ React Component │
|
|
279
|
-
│ (Structura) │
|
|
280
|
-
└────────┬─────────┘
|
|
281
|
-
│
|
|
282
|
-
├─── PDF Viewer (Left)
|
|
283
|
-
│ - Render PDF pages
|
|
284
|
-
│ - Click to highlight
|
|
285
|
-
│
|
|
286
|
-
└─── HTML Viewer (Right)
|
|
287
|
-
- Structured content
|
|
288
|
-
- Inline editing
|
|
289
|
-
- Save button
|
|
290
|
-
│
|
|
291
|
-
▼
|
|
292
|
-
┌──────────────┐
|
|
293
|
-
│ Express API │
|
|
294
|
-
│ (port 3002) │
|
|
295
|
-
└──────┬───────┘
|
|
296
|
-
│
|
|
297
|
-
▼
|
|
298
|
-
┌──────────────┐
|
|
299
|
-
│ SQLite DB │
|
|
300
|
-
│ (edits.db) │
|
|
301
|
-
└──────────────┘
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
## Production Deployment
|
|
305
|
-
|
|
306
|
-
### Using PM2
|
|
307
|
-
|
|
308
|
-
```bash
|
|
309
|
-
npm install -g pm2
|
|
310
|
-
pm2 start server/server.js --name structura-server
|
|
311
|
-
pm2 save
|
|
312
|
-
pm2 startup
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Docker
|
|
316
|
-
|
|
317
|
-
```dockerfile
|
|
318
|
-
FROM node:18
|
|
319
|
-
WORKDIR /app
|
|
320
|
-
COPY package*.json ./
|
|
321
|
-
RUN npm install --production
|
|
322
|
-
COPY . .
|
|
323
|
-
EXPOSE 3002
|
|
324
|
-
CMD ["node", "server/server.js"]
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### Nginx
|
|
328
|
-
|
|
329
|
-
```nginx
|
|
330
|
-
location /api/ {
|
|
331
|
-
proxy_pass http://localhost:3002;
|
|
332
|
-
client_max_body_size 50M;
|
|
106
|
+
// Check for math content
|
|
107
|
+
if (containsMath(text)) {
|
|
108
|
+
// handle math
|
|
333
109
|
}
|
|
334
110
|
```
|
|
335
111
|
|
|
336
|
-
##
|
|
337
|
-
|
|
338
|
-
### Environment Variables
|
|
339
|
-
|
|
340
|
-
```bash
|
|
341
|
-
PORT=3002 # Server port
|
|
342
|
-
NODE_ENV=production # Environment
|
|
343
|
-
DATABASE_PATH=./edits.db # SQLite path
|
|
344
|
-
MAX_JSON_SIZE=50mb # Request limit
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
## Troubleshooting
|
|
348
|
-
|
|
349
|
-
### Save button not appearing
|
|
350
|
-
|
|
351
|
-
1. Check `onSave` prop is provided
|
|
352
|
-
2. Make an edit (double-click text)
|
|
353
|
-
3. Rebuild library: `npm run build`
|
|
112
|
+
## Semantic Tags
|
|
354
113
|
|
|
355
|
-
|
|
114
|
+
Parse and render semantic tags for document corrections:
|
|
356
115
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
3. Check browser console for errors
|
|
116
|
+
```jsx
|
|
117
|
+
import { SemanticTagRenderer, parseSemanticTags } from '@tfw.in/structura-lib';
|
|
360
118
|
|
|
361
|
-
|
|
119
|
+
// Render with visual highlighting
|
|
120
|
+
<SemanticTagRenderer content="Text with <add>additions</add> and <del>deletions</del>" />
|
|
362
121
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
122
|
+
// Parse tags programmatically
|
|
123
|
+
const parsed = parseSemanticTags(content);
|
|
124
|
+
```
|
|
366
125
|
|
|
367
126
|
## License
|
|
368
127
|
|
|
369
128
|
MIT
|
|
370
|
-
|
|
371
|
-
## Author
|
|
372
|
-
|
|
373
|
-
TFW
|
|
374
|
-
|
|
375
|
-
## Support
|
|
376
|
-
|
|
377
|
-
For issues and questions:
|
|
378
|
-
- GitHub: https://github.com/ChakshuGautam/structura-lib
|
|
379
|
-
- Documentation: See `/server/README.md` for API details
|
|
@@ -4,6 +4,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var React = require('react');
|
|
7
|
+
var SemanticTagRenderer = require('./SemanticTagRenderer.js');
|
|
8
|
+
var SemanticTagParser = require('./SemanticTagParser.js');
|
|
9
|
+
var MathRenderer = require('./MathRenderer.js');
|
|
7
10
|
|
|
8
11
|
// Helper function to extract text content while preserving structure
|
|
9
12
|
const extractTextPreservingStructure = html => {
|
|
@@ -25,7 +28,13 @@ function EditableContent({
|
|
|
25
28
|
content,
|
|
26
29
|
onContentChange,
|
|
27
30
|
isHeading = false,
|
|
28
|
-
|
|
31
|
+
isEditMode = false,
|
|
32
|
+
isJsonMode = false,
|
|
33
|
+
onNodeClick,
|
|
34
|
+
onJsonClick,
|
|
35
|
+
enableSemanticTags = true,
|
|
36
|
+
onSemanticTagClick,
|
|
37
|
+
enableMathRendering = true
|
|
29
38
|
}) {
|
|
30
39
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
31
40
|
const [editedContent, setEditedContent] = React.useState(content);
|
|
@@ -55,24 +64,22 @@ function EditableContent({
|
|
|
55
64
|
const getHeadingStyles = level => {
|
|
56
65
|
switch (level) {
|
|
57
66
|
case 1:
|
|
58
|
-
return "text-2xl font-bold";
|
|
59
|
-
case 2:
|
|
60
67
|
return "text-xl font-bold";
|
|
61
|
-
case
|
|
68
|
+
case 2:
|
|
62
69
|
return "text-lg font-bold";
|
|
63
|
-
case
|
|
70
|
+
case 3:
|
|
64
71
|
return "text-base font-bold";
|
|
65
|
-
case
|
|
72
|
+
case 4:
|
|
66
73
|
return "text-sm font-bold";
|
|
67
|
-
case
|
|
74
|
+
case 5:
|
|
68
75
|
return "text-xs font-bold";
|
|
76
|
+
case 6:
|
|
77
|
+
return "text-xs font-semibold";
|
|
69
78
|
default:
|
|
70
|
-
return "text-
|
|
79
|
+
return "text-sm";
|
|
71
80
|
}
|
|
72
81
|
};
|
|
73
|
-
const
|
|
74
|
-
// Stop propagation to prevent parent click handlers from firing
|
|
75
|
-
e.stopPropagation();
|
|
82
|
+
const startEditing = () => {
|
|
76
83
|
if (onContentChange) {
|
|
77
84
|
// Extract text content for textarea while preserving structure
|
|
78
85
|
setTextAreaContent(extractTextPreservingStructure(editedContent));
|
|
@@ -111,6 +118,18 @@ function EditableContent({
|
|
|
111
118
|
e.stopPropagation();
|
|
112
119
|
return;
|
|
113
120
|
}
|
|
121
|
+
// In JSON mode, show JSON on click
|
|
122
|
+
if (isJsonMode && onJsonClick) {
|
|
123
|
+
e.stopPropagation();
|
|
124
|
+
onJsonClick();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// In edit mode, single click activates editing
|
|
128
|
+
if (isEditMode && onContentChange) {
|
|
129
|
+
e.stopPropagation();
|
|
130
|
+
startEditing();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
114
133
|
// If there's an onNodeClick handler, call it
|
|
115
134
|
if (onNodeClick) {
|
|
116
135
|
e.stopPropagation(); // Prevent click from reaching parent containers
|
|
@@ -124,25 +143,34 @@ function EditableContent({
|
|
|
124
143
|
handleBlur();
|
|
125
144
|
}
|
|
126
145
|
};
|
|
146
|
+
// Render math expressions in content (conditionally)
|
|
147
|
+
const renderedContent = React.useMemo(() => {
|
|
148
|
+
return enableMathRendering ? MathRenderer.renderMathInHtml(editedContent) : editedContent;
|
|
149
|
+
}, [editedContent, enableMathRendering]);
|
|
127
150
|
return jsxRuntime.jsx("div", {
|
|
128
|
-
className: `w-full ${isEdited ? "bg-yellow-100" : ""} ${onNodeClick && !isEditing ? "cursor-pointer" : ""}`,
|
|
151
|
+
className: `w-full ${isEdited ? "bg-yellow-100" : ""} ${isJsonMode ? "cursor-pointer hover:bg-purple-50 border border-transparent hover:border-purple-300 rounded" : ""} ${isEditMode && !isEditing ? "cursor-pointer hover:bg-blue-50 border border-transparent hover:border-blue-300 rounded" : ""} ${onNodeClick && !isEditing && !isEditMode && !isJsonMode ? "cursor-pointer" : ""}`,
|
|
129
152
|
onClick: handleClick,
|
|
130
|
-
onDoubleClick: handleDoubleClick,
|
|
131
153
|
children: isEditing ? jsxRuntime.jsx("textarea", {
|
|
132
154
|
value: textAreaContent,
|
|
133
155
|
onChange: handleChange,
|
|
134
156
|
onBlur: handleBlur,
|
|
135
157
|
onKeyDown: handleKeyDown,
|
|
136
158
|
autoFocus: true,
|
|
137
|
-
className: "w-full p-1 border border-blue-400 rounded focus:outline-none focus:ring-2 focus:ring-blue-500
|
|
159
|
+
className: "w-full p-1 border border-blue-400 rounded focus:outline-none focus:ring-2 focus:ring-blue-500",
|
|
138
160
|
onClick: e => e.stopPropagation(),
|
|
139
161
|
rows: 3
|
|
140
162
|
}) : jsxRuntime.jsx("div", {
|
|
141
163
|
ref: contentRef,
|
|
142
|
-
className: `prose max-w-none ${isHeading ? getHeadingStyles(headingLevel) : ""}`,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
164
|
+
className: `prose prose-sm max-w-none ${isHeading ? getHeadingStyles(headingLevel) : "text-sm"}`,
|
|
165
|
+
children: enableSemanticTags && SemanticTagParser.hasSemanticTags(editedContent) ? jsxRuntime.jsx(SemanticTagRenderer.default, {
|
|
166
|
+
content: editedContent,
|
|
167
|
+
showTooltips: true,
|
|
168
|
+
onTagClick: onSemanticTagClick
|
|
169
|
+
}) : jsxRuntime.jsx("span", {
|
|
170
|
+
dangerouslySetInnerHTML: {
|
|
171
|
+
__html: renderedContent
|
|
172
|
+
}
|
|
173
|
+
})
|
|
146
174
|
})
|
|
147
175
|
});
|
|
148
176
|
}
|