react-native-nitro-markdown 0.5.8 → 0.6.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.
- package/README.md +13 -26
- package/android/CMakeLists.txt +1 -1
- package/android/build.gradle +2 -2
- package/android/consumer-rules.pro +1 -1
- package/android/gradle.properties +1 -2
- package/android/src/main/java/com/margelo/nitro/com/nitromarkdown/HybridMarkdownSession.kt +8 -1
- package/ios/HybridMarkdownSession.swift +17 -0
- package/lib/commonjs/markdown.js +6 -0
- package/lib/commonjs/markdown.js.map +1 -1
- package/lib/commonjs/renderers/math.js +33 -78
- package/lib/commonjs/renderers/math.js.map +1 -1
- package/lib/module/markdown.js +6 -0
- package/lib/module/markdown.js.map +1 -1
- package/lib/module/renderers/math.js +33 -78
- package/lib/module/renderers/math.js.map +1 -1
- package/lib/typescript/commonjs/markdown.d.ts.map +1 -1
- package/lib/typescript/commonjs/renderers/math.d.ts.map +1 -1
- package/lib/typescript/module/markdown.d.ts.map +1 -1
- package/lib/typescript/module/renderers/math.d.ts.map +1 -1
- package/package.json +3 -13
- package/react-native-nitro-markdown.podspec +7 -8
- package/src/markdown.tsx +6 -0
- package/src/renderers/math.tsx +40 -97
- package/cpp/bindings/HybridMarkdownSession.cpp +0 -2
- package/cpp/core/MarkdownSessionCore.cpp +0 -2
package/src/renderers/math.tsx
CHANGED
|
@@ -14,35 +14,24 @@ import { getCachedStyles } from "./style-cache";
|
|
|
14
14
|
import { useMarkdownContext } from "../MarkdownContext";
|
|
15
15
|
import type { MarkdownTheme } from "../theme";
|
|
16
16
|
|
|
17
|
-
let
|
|
17
|
+
let RaTeXViewComponent: ComponentType<{
|
|
18
|
+
latex: string;
|
|
18
19
|
fontSize?: number;
|
|
20
|
+
displayMode?: boolean;
|
|
19
21
|
color?: string;
|
|
20
|
-
fontCache?: boolean;
|
|
21
22
|
style?: StyleProp<ViewStyle>;
|
|
22
|
-
|
|
23
|
-
height?: number;
|
|
24
|
-
children?: string;
|
|
23
|
+
onError?: (event: { nativeEvent: { error: string } }) => void;
|
|
25
24
|
}> | null = null;
|
|
26
|
-
let SvgFromXmlComponent: ComponentType<{
|
|
27
|
-
xml: string;
|
|
28
|
-
width?: number;
|
|
29
|
-
height?: number;
|
|
30
|
-
style?: StyleProp<ViewStyle>;
|
|
31
|
-
}> | null = null;
|
|
32
|
-
let texToSvg: ((textext: string, fontSize?: number) => string) | null = null;
|
|
33
25
|
|
|
34
26
|
try {
|
|
35
27
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
texToSvg = mathJaxModule.texToSvg ?? null;
|
|
39
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
|
-
SvgFromXmlComponent = require("react-native-svg").SvgFromXml;
|
|
28
|
+
const ratexModule = require("ratex-react-native");
|
|
29
|
+
RaTeXViewComponent = ratexModule.RaTeXView ?? null;
|
|
41
30
|
} catch {
|
|
42
31
|
if (__DEV__) {
|
|
43
32
|
// eslint-disable-next-line no-console
|
|
44
33
|
console.warn(
|
|
45
|
-
"[NitroMarkdown] react-native
|
|
34
|
+
"[NitroMarkdown] ratex-react-native not found — math will render as plain text.",
|
|
46
35
|
);
|
|
47
36
|
}
|
|
48
37
|
}
|
|
@@ -55,34 +44,13 @@ type MathInlineProps = {
|
|
|
55
44
|
type MathStyles = ReturnType<typeof createMathStyles>;
|
|
56
45
|
|
|
57
46
|
const mathStylesCache = new WeakMap<MarkdownTheme, MathStyles>();
|
|
58
|
-
const
|
|
59
|
-
|
|
47
|
+
const INLINE_DISPLAY_MATH_PATTERN =
|
|
48
|
+
/\\(?:frac|dfrac|tfrac|sqrt|sum|prod|int|lim|begin|matrix|pmatrix|bmatrix|cases)\b/;
|
|
60
49
|
|
|
61
|
-
function
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
function createMathSvg(
|
|
66
|
-
content: string,
|
|
67
|
-
fontSize: number,
|
|
68
|
-
color: string | undefined,
|
|
69
|
-
) {
|
|
70
|
-
if (!texToSvg) return null;
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
const xml = colorizeSvg(texToSvg(content, fontSize / 2), color);
|
|
74
|
-
const widthMatch = SVG_WIDTH_PATTERN.exec(xml);
|
|
75
|
-
const heightMatch = SVG_HEIGHT_PATTERN.exec(xml);
|
|
76
|
-
if (!widthMatch || !heightMatch) return null;
|
|
77
|
-
|
|
78
|
-
const width = Number.parseFloat(widthMatch[1]);
|
|
79
|
-
const height = Number.parseFloat(heightMatch[1]);
|
|
80
|
-
if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
|
|
81
|
-
|
|
82
|
-
return { xml, width, height };
|
|
83
|
-
} catch {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
50
|
+
function getInlineMathFontSize(content: string, theme: MarkdownTheme) {
|
|
51
|
+
return INLINE_DISPLAY_MATH_PATTERN.test(content)
|
|
52
|
+
? theme.fontSizes.xl + 2
|
|
53
|
+
: theme.fontSizes.l;
|
|
86
54
|
}
|
|
87
55
|
|
|
88
56
|
type HorizontalMathViewportProps = {
|
|
@@ -218,6 +186,10 @@ const createMathStyles = (theme: MarkdownTheme) =>
|
|
|
218
186
|
color: theme.colors.code,
|
|
219
187
|
...(Platform.OS === "android" && { includeFontPadding: false }),
|
|
220
188
|
},
|
|
189
|
+
ratexInline: {
|
|
190
|
+
backgroundColor: "transparent",
|
|
191
|
+
flexShrink: 0,
|
|
192
|
+
},
|
|
221
193
|
mathBlockContainer: {
|
|
222
194
|
width: "100%",
|
|
223
195
|
maxWidth: "100%",
|
|
@@ -229,7 +201,6 @@ const createMathStyles = (theme: MarkdownTheme) =>
|
|
|
229
201
|
borderRadius: theme.borderRadius.l,
|
|
230
202
|
borderWidth: 1,
|
|
231
203
|
borderColor: theme.colors.border,
|
|
232
|
-
// Ensure we don't collapse if MathJax fails to report size immediately
|
|
233
204
|
minHeight: 48,
|
|
234
205
|
overflow: "hidden",
|
|
235
206
|
},
|
|
@@ -244,10 +215,8 @@ const createMathStyles = (theme: MarkdownTheme) =>
|
|
|
244
215
|
alignItems: "center",
|
|
245
216
|
justifyContent: "center",
|
|
246
217
|
},
|
|
247
|
-
|
|
218
|
+
ratexBlock: {
|
|
248
219
|
backgroundColor: "transparent",
|
|
249
|
-
},
|
|
250
|
-
mathBlockSvgFrame: {
|
|
251
220
|
flexShrink: 0,
|
|
252
221
|
},
|
|
253
222
|
mathBlockFallbackContainer: {
|
|
@@ -278,21 +247,23 @@ const createMathStyles = (theme: MarkdownTheme) =>
|
|
|
278
247
|
export const MathInline: FC<MathInlineProps> = ({ content, style }) => {
|
|
279
248
|
const { theme } = useMarkdownContext();
|
|
280
249
|
const styles = getCachedStyles(mathStylesCache, theme, createMathStyles);
|
|
250
|
+
const [hasRenderError, setHasRenderError] = useState(false);
|
|
281
251
|
|
|
282
252
|
if (!content) return null;
|
|
283
253
|
|
|
284
|
-
if (
|
|
285
|
-
const fontSize = theme.fontSizes.s;
|
|
254
|
+
if (RaTeXViewComponent && !hasRenderError) {
|
|
286
255
|
return (
|
|
287
256
|
<View style={[styles.mathInlineContainer, style]}>
|
|
288
|
-
<
|
|
289
|
-
|
|
257
|
+
<RaTeXViewComponent
|
|
258
|
+
latex={content}
|
|
259
|
+
fontSize={getInlineMathFontSize(content, theme)}
|
|
260
|
+
displayMode={false}
|
|
290
261
|
color={theme.colors.text}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
262
|
+
style={styles.ratexInline}
|
|
263
|
+
onError={() => {
|
|
264
|
+
setHasRenderError(true);
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
296
267
|
</View>
|
|
297
268
|
);
|
|
298
269
|
}
|
|
@@ -312,55 +283,27 @@ type MathBlockProps = {
|
|
|
312
283
|
export const MathBlock: FC<MathBlockProps> = ({ content, style }) => {
|
|
313
284
|
const { theme } = useMarkdownContext();
|
|
314
285
|
const styles = getCachedStyles(mathStylesCache, theme, createMathStyles);
|
|
286
|
+
const [hasRenderError, setHasRenderError] = useState(false);
|
|
315
287
|
|
|
316
288
|
if (!content) return null;
|
|
317
289
|
|
|
318
|
-
|
|
319
|
-
const blockSvg =
|
|
320
|
-
SvgFromXmlComponent &&
|
|
321
|
-
createMathSvg(displayContent, theme.fontSizes.l, theme.colors.text);
|
|
322
|
-
|
|
323
|
-
if (blockSvg && SvgFromXmlComponent) {
|
|
324
|
-
return (
|
|
325
|
-
<View style={[styles.mathBlockContainer, style]}>
|
|
326
|
-
<HorizontalMathViewport
|
|
327
|
-
style={styles.mathBlockScroll}
|
|
328
|
-
contentStyle={styles.mathBlockScrollContent}
|
|
329
|
-
contentWidth={blockSvg.width}
|
|
330
|
-
>
|
|
331
|
-
<View
|
|
332
|
-
style={[
|
|
333
|
-
styles.mathBlockSvgFrame,
|
|
334
|
-
{ width: blockSvg.width, height: blockSvg.height },
|
|
335
|
-
]}
|
|
336
|
-
>
|
|
337
|
-
<SvgFromXmlComponent
|
|
338
|
-
xml={blockSvg.xml}
|
|
339
|
-
width={blockSvg.width}
|
|
340
|
-
height={blockSvg.height}
|
|
341
|
-
style={styles.mathBlockSvg}
|
|
342
|
-
/>
|
|
343
|
-
</View>
|
|
344
|
-
</HorizontalMathViewport>
|
|
345
|
-
</View>
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
if (MathJaxComponent) {
|
|
290
|
+
if (RaTeXViewComponent && !hasRenderError) {
|
|
350
291
|
return (
|
|
351
292
|
<View style={[styles.mathBlockContainer, style]}>
|
|
352
293
|
<HorizontalMathViewport
|
|
353
294
|
style={styles.mathBlockScroll}
|
|
354
295
|
contentStyle={styles.mathBlockScrollContent}
|
|
355
296
|
>
|
|
356
|
-
<
|
|
357
|
-
|
|
297
|
+
<RaTeXViewComponent
|
|
298
|
+
latex={content}
|
|
299
|
+
fontSize={theme.fontSizes.xl}
|
|
300
|
+
displayMode
|
|
358
301
|
color={theme.colors.text}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
302
|
+
style={styles.ratexBlock}
|
|
303
|
+
onError={() => {
|
|
304
|
+
setHasRenderError(true);
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
364
307
|
</HorizontalMathViewport>
|
|
365
308
|
</View>
|
|
366
309
|
);
|