@tfw.in/structura-lib 0.2.5 → 0.2.6

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 CHANGED
@@ -121,28 +121,49 @@ function App() {
121
121
 
122
122
  ## Math Rendering
123
123
 
124
- The library automatically renders LaTeX math expressions in content:
124
+ The Structura component automatically renders LaTeX math expressions (`$m^2$`, `$L/m^2$`, etc.) when `mathRendering={true}` (the default).
125
125
 
126
- - Inline math: `$x^2 + y^2 = z^2$`
127
- - Display math: `$$\sum_{i=1}^{n} x_i$$`
126
+ If you extract text from the response structure (e.g. Gemini corrected output) and render it in your own components, the raw LaTeX delimiters will appear as plain text. Use `renderMathInHtml` to convert them to rendered math:
128
127
 
129
- You can also use the math utilities directly:
128
+ ```jsx
129
+ import { renderMathInHtml } from '@tfw.in/structura-lib';
130
+
131
+ // Convert LaTeX delimiters to rendered HTML
132
+ const rawText = "Total membrane area required 0.02$m^2$";
133
+ const rendered = renderMathInHtml(rawText);
134
+ // Use with dangerouslySetInnerHTML
135
+ <div dangerouslySetInnerHTML={{ __html: rendered }} />
136
+ ```
137
+
138
+ ### Utilities
139
+
140
+ | Export | Type | Description |
141
+ |--------|------|-------------|
142
+ | `renderMathInHtml(html)` | `function` | Converts `$...$` (inline) and `$$...$$` (display) math to KaTeX HTML. Use this when rendering extracted text in your own components. |
143
+ | `containsMath(html)` | `function` | Returns `true` if the string contains math delimiters. |
144
+ | `MathContent` | `React component` | Renders HTML with math expressions. Props: `html`, `className`, `as` (element type). |
145
+ | `useMathHtml(html)` | `React hook` | Returns rendered math HTML string via `useMemo`. |
130
146
 
131
147
  ```jsx
132
- import { MathContent, renderMathInHtml, containsMath } from '@tfw.in/structura-lib';
148
+ import { MathContent, renderMathInHtml, containsMath, useMathHtml } from '@tfw.in/structura-lib';
133
149
 
134
- // React component
150
+ // As a React component
135
151
  <MathContent html="The formula is $E = mc^2$" />
136
152
 
137
- // Utility function
138
- const rendered = renderMathInHtml("Price is $20$ dollars");
153
+ // As a hook
154
+ function MyComponent({ text }) {
155
+ const rendered = useMathHtml(text);
156
+ return <span dangerouslySetInnerHTML={{ __html: rendered }} />;
157
+ }
139
158
 
140
- // Check for math content
159
+ // Check before processing
141
160
  if (containsMath(text)) {
142
- // handle math
161
+ const html = renderMathInHtml(text);
143
162
  }
144
163
  ```
145
164
 
165
+ > **Note:** Ensure you import the library styles (`@tfw.in/structura-lib/styles.css`) — this loads the KaTeX CSS required for proper math rendering.
166
+
146
167
  ## Semantic Tags
147
168
 
148
169
  Parse and render semantic tags for document corrections:
@@ -8,6 +8,7 @@ var vsc = require('react-icons/vsc');
8
8
  var index_esm = require('./node_modules/react-icons/fa/index.esm.js');
9
9
  var Table = require('./Table.js');
10
10
  var EditableContent = require('./EditableContent.js');
11
+ var MathRenderer = require('./MathRenderer.js');
11
12
  var accuracyMetrics = require('./accuracyMetrics.js');
12
13
  var SemanticTagParser = require('./SemanticTagParser.js');
13
14
 
@@ -248,19 +249,19 @@ const FaTagsIcon = index_esm.FaTags;
248
249
  function GeminiCorrectedBlock({
249
250
  html,
250
251
  isEditMode,
251
- onContentChange
252
+ onContentChange,
253
+ enableMathRendering = true
252
254
  }) {
253
255
  const ref = React.useRef(null);
254
- console.log('[GeminiCorrectedBlock] render isEditMode:', isEditMode, 'htmlLength:', html === null || html === void 0 ? void 0 : html.length, 'ref.current:', !!ref.current);
256
+ const processedHtml = React.useMemo(() => {
257
+ return enableMathRendering ? MathRenderer.renderMathInHtml(html) : html;
258
+ }, [html, enableMathRendering]);
255
259
  // Set initial HTML only once via ref — never via dangerouslySetInnerHTML on a contentEditable
256
260
  React.useEffect(() => {
257
- var _a;
258
- console.log('[GeminiCorrectedBlock] useEffect — ref.current:', !!ref.current, 'html matches:', ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.innerHTML) === html);
259
- if (ref.current && ref.current.innerHTML !== html) {
260
- ref.current.innerHTML = html;
261
- console.log('[GeminiCorrectedBlock] innerHTML set, length:', ref.current.innerHTML.length);
261
+ if (ref.current && ref.current.innerHTML !== processedHtml) {
262
+ ref.current.innerHTML = processedHtml;
262
263
  }
263
- }, [html]);
264
+ }, [processedHtml]);
264
265
  React.useEffect(() => {
265
266
  var _a;
266
267
  console.log('[GeminiCorrectedBlock] isEditMode changed to:', isEditMode, '— contentEditable on div:', (_a = ref.current) === null || _a === void 0 ? void 0 : _a.contentEditable);
@@ -665,7 +666,8 @@ function HtmlViewer({
665
666
  }) : ((_b = node.id) === null || _b === void 0 ? void 0 : _b.endsWith('/GeminiCorrected')) ? jsxRuntime.jsx(GeminiCorrectedBlock, {
666
667
  html: node.html || '',
667
668
  isEditMode: viewMode === 'edit',
668
- onContentChange: newHtml => handleContentChange(node.id, newHtml)
669
+ onContentChange: newHtml => handleContentChange(node.id, newHtml),
670
+ enableMathRendering: enableMathRendering
669
671
  }) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
670
672
  children: [jsxRuntime.jsx(EditableContent.default, {
671
673
  id: node.id,
@@ -5,6 +5,7 @@ import { VscJson } from 'react-icons/vsc';
5
5
  import { FaEdit, FaTags, FaFileDownload, FaChartBar } from './node_modules/react-icons/fa/index.esm.js';
6
6
  import Table from './Table.js';
7
7
  import EditableContent from './EditableContent.js';
8
+ import { renderMathInHtml } from './MathRenderer.js';
8
9
  import { calculateDifferences } from './accuracyMetrics.js';
9
10
  import { getTagTypeInfo } from './SemanticTagParser.js';
10
11
 
@@ -247,18 +248,19 @@ var FaTagsIcon = FaTags;
247
248
  function GeminiCorrectedBlock(_ref6) {
248
249
  var html = _ref6.html,
249
250
  isEditMode = _ref6.isEditMode,
250
- onContentChange = _ref6.onContentChange;
251
+ onContentChange = _ref6.onContentChange,
252
+ _ref6$enableMathRende = _ref6.enableMathRendering,
253
+ enableMathRendering = _ref6$enableMathRende === void 0 ? true : _ref6$enableMathRende;
251
254
  var ref = useRef(null);
252
- console.log('[GeminiCorrectedBlock] render isEditMode:', isEditMode, 'htmlLength:', html === null || html === void 0 ? void 0 : html.length, 'ref.current:', !!ref.current);
255
+ var processedHtml = useMemo(function () {
256
+ return enableMathRendering ? renderMathInHtml(html) : html;
257
+ }, [html, enableMathRendering]);
253
258
  // Set initial HTML only once via ref — never via dangerouslySetInnerHTML on a contentEditable
254
259
  useEffect(function () {
255
- var _a;
256
- console.log('[GeminiCorrectedBlock] useEffect — ref.current:', !!ref.current, 'html matches:', ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.innerHTML) === html);
257
- if (ref.current && ref.current.innerHTML !== html) {
258
- ref.current.innerHTML = html;
259
- console.log('[GeminiCorrectedBlock] innerHTML set, length:', ref.current.innerHTML.length);
260
+ if (ref.current && ref.current.innerHTML !== processedHtml) {
261
+ ref.current.innerHTML = processedHtml;
260
262
  }
261
- }, [html]);
263
+ }, [processedHtml]);
262
264
  useEffect(function () {
263
265
  var _a;
264
266
  console.log('[GeminiCorrectedBlock] isEditMode changed to:', isEditMode, '— contentEditable on div:', (_a = ref.current) === null || _a === void 0 ? void 0 : _a.contentEditable);
@@ -748,7 +750,8 @@ function HtmlViewer(_ref7) {
748
750
  isEditMode: viewMode === 'edit',
749
751
  onContentChange: function onContentChange(newHtml) {
750
752
  return handleContentChange(node.id, newHtml);
751
- }
753
+ },
754
+ enableMathRendering: enableMathRendering
752
755
  }) : jsxs(Fragment, {
753
756
  children: [jsx(EditableContent, {
754
757
  id: node.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tfw.in/structura-lib",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Structura Library Components",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -29,8 +29,8 @@
29
29
  "test:watch": "vitest"
30
30
  },
31
31
  "peerDependencies": {
32
- "react": "^18.2.0",
33
- "react-dom": "^18.2.0",
32
+ "react": "^18.2.0 || ^19.0.0",
33
+ "react-dom": "^18.2.0 || ^19.0.0",
34
34
  "tailwindcss": "^3.3.0"
35
35
  },
36
36
  "dependencies": {
@@ -44,7 +44,7 @@
44
44
  "class-variance-authority": "^0.7.0",
45
45
  "katex": "^0.16.27",
46
46
  "lucide-react": "^0.509.0",
47
- "pdfjs-dist": "4.8.69",
47
+ "pdfjs-dist": "^4.8.69",
48
48
  "postcss-cli": "^11.0.1",
49
49
  "react-icons": "^4.12.0",
50
50
  "react-pdf": "^9.2.1",