react-native-enriched-markdown 0.1.0 → 0.2.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/LICENSE +20 -0
- package/README.md +551 -0
- package/ReactNativeEnrichedMarkdown.podspec +27 -0
- package/android/build.gradle +101 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +54 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +26 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +82 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1388 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/baseline-prof.txt +65 -0
- package/android/src/main/cpp/jni-adapter.cpp +220 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +270 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +173 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +385 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +279 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLongPressEvent.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +31 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +62 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +84 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +104 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +36 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +70 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +68 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +29 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +59 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +76 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +103 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +80 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +109 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +86 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrikethroughRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +45 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/UnderlineRenderer.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +321 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +51 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrikethroughSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +51 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +54 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrikethroughStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +211 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +92 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/TextAlignment.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/UnderlineStyle.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +827 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/LinkLongPressMovementMethod.kt +121 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +375 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +183 -0
- package/android/src/main/jni/CMakeLists.txt +70 -0
- package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
- package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +20 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +37 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +22 -0
- package/cpp/md4c/md4c.c +6492 -0
- package/cpp/md4c/md4c.h +402 -0
- package/cpp/parser/MD4CParser.cpp +327 -0
- package/cpp/parser/MD4CParser.hpp +27 -0
- package/cpp/parser/MarkdownASTNode.hpp +51 -0
- package/ios/EnrichedMarkdownText.h +18 -0
- package/ios/EnrichedMarkdownText.mm +1401 -0
- package/ios/attachments/EnrichedMarkdownImageAttachment.h +23 -0
- package/ios/attachments/EnrichedMarkdownImageAttachment.m +185 -0
- package/ios/attachments/ThematicBreakAttachment.h +15 -0
- package/ios/attachments/ThematicBreakAttachment.m +33 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
- package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
- package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
- package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +82 -0
- package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1388 -0
- package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
- package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
- package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
- package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
- package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
- package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
- package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
- package/ios/internals/EnrichedMarkdownTextState.h +24 -0
- package/ios/parser/MarkdownASTNode.h +35 -0
- package/ios/parser/MarkdownASTNode.m +32 -0
- package/ios/parser/MarkdownParser.h +17 -0
- package/ios/parser/MarkdownParser.mm +42 -0
- package/ios/parser/MarkdownParserBridge.mm +120 -0
- package/ios/renderer/AttributedRenderer.h +11 -0
- package/ios/renderer/AttributedRenderer.m +152 -0
- package/ios/renderer/BlockquoteRenderer.h +7 -0
- package/ios/renderer/BlockquoteRenderer.m +160 -0
- package/ios/renderer/CodeBlockRenderer.h +10 -0
- package/ios/renderer/CodeBlockRenderer.m +90 -0
- package/ios/renderer/CodeRenderer.h +10 -0
- package/ios/renderer/CodeRenderer.m +60 -0
- package/ios/renderer/EmphasisRenderer.h +6 -0
- package/ios/renderer/EmphasisRenderer.m +96 -0
- package/ios/renderer/HeadingRenderer.h +7 -0
- package/ios/renderer/HeadingRenderer.m +105 -0
- package/ios/renderer/ImageRenderer.h +12 -0
- package/ios/renderer/ImageRenderer.m +83 -0
- package/ios/renderer/LinkRenderer.h +7 -0
- package/ios/renderer/LinkRenderer.m +69 -0
- package/ios/renderer/ListItemRenderer.h +16 -0
- package/ios/renderer/ListItemRenderer.m +103 -0
- package/ios/renderer/ListRenderer.h +13 -0
- package/ios/renderer/ListRenderer.m +70 -0
- package/ios/renderer/NodeRenderer.h +8 -0
- package/ios/renderer/ParagraphRenderer.h +7 -0
- package/ios/renderer/ParagraphRenderer.m +80 -0
- package/ios/renderer/RenderContext.h +105 -0
- package/ios/renderer/RenderContext.m +312 -0
- package/ios/renderer/RendererFactory.h +12 -0
- package/ios/renderer/RendererFactory.m +116 -0
- package/ios/renderer/StrikethroughRenderer.h +6 -0
- package/ios/renderer/StrikethroughRenderer.m +40 -0
- package/ios/renderer/StrongRenderer.h +6 -0
- package/ios/renderer/StrongRenderer.m +83 -0
- package/ios/renderer/TextRenderer.h +6 -0
- package/ios/renderer/TextRenderer.m +16 -0
- package/ios/renderer/ThematicBreakRenderer.h +5 -0
- package/ios/renderer/ThematicBreakRenderer.m +53 -0
- package/ios/renderer/UnderlineRenderer.h +6 -0
- package/ios/renderer/UnderlineRenderer.m +39 -0
- package/ios/styles/StyleConfig.h +274 -0
- package/ios/styles/StyleConfig.mm +1806 -0
- package/ios/utils/AccessibilityInfo.h +35 -0
- package/ios/utils/AccessibilityInfo.m +24 -0
- package/ios/utils/BlockquoteBorder.h +20 -0
- package/ios/utils/BlockquoteBorder.m +92 -0
- package/ios/utils/CodeBackground.h +19 -0
- package/ios/utils/CodeBackground.m +191 -0
- package/ios/utils/CodeBlockBackground.h +17 -0
- package/ios/utils/CodeBlockBackground.m +82 -0
- package/ios/utils/EditMenuUtils.h +22 -0
- package/ios/utils/EditMenuUtils.m +118 -0
- package/ios/utils/FontUtils.h +25 -0
- package/ios/utils/FontUtils.m +27 -0
- package/ios/utils/HTMLGenerator.h +20 -0
- package/ios/utils/HTMLGenerator.m +793 -0
- package/ios/utils/LastElementUtils.h +53 -0
- package/ios/utils/ListMarkerDrawer.h +15 -0
- package/ios/utils/ListMarkerDrawer.m +127 -0
- package/ios/utils/MarkdownAccessibilityElementBuilder.h +45 -0
- package/ios/utils/MarkdownAccessibilityElementBuilder.m +323 -0
- package/ios/utils/MarkdownExtractor.h +17 -0
- package/ios/utils/MarkdownExtractor.m +308 -0
- package/ios/utils/ParagraphStyleUtils.h +21 -0
- package/ios/utils/ParagraphStyleUtils.m +111 -0
- package/ios/utils/PasteboardUtils.h +36 -0
- package/ios/utils/PasteboardUtils.m +134 -0
- package/ios/utils/RTFExportUtils.h +24 -0
- package/ios/utils/RTFExportUtils.m +297 -0
- package/ios/utils/RuntimeKeys.h +38 -0
- package/ios/utils/RuntimeKeys.m +11 -0
- package/ios/utils/TextViewLayoutManager.h +14 -0
- package/ios/utils/TextViewLayoutManager.mm +113 -0
- package/lib/module/EnrichedMarkdownText.js +65 -0
- package/lib/module/EnrichedMarkdownText.js.map +1 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +210 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/normalizeMarkdownStyle.js +384 -0
- package/lib/module/normalizeMarkdownStyle.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/EnrichedMarkdownText.d.ts +183 -0
- package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +185 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
- package/package.json +186 -1
- package/react-native.config.js +13 -0
- package/src/EnrichedMarkdownText.tsx +280 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +210 -0
- package/src/index.tsx +10 -0
- package/src/normalizeMarkdownStyle.ts +423 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
package com.swmansion.enriched.markdown.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
import android.text.SpannableString
|
|
6
|
+
import android.text.SpannableStringBuilder
|
|
7
|
+
import android.text.TextPaint
|
|
8
|
+
import com.facebook.react.bridge.ReadableMap
|
|
9
|
+
import com.facebook.react.common.ReactConstants
|
|
10
|
+
import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
|
|
11
|
+
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
|
12
|
+
import com.swmansion.enriched.markdown.parser.MarkdownASTNode
|
|
13
|
+
import com.swmansion.enriched.markdown.renderer.BlockStyle
|
|
14
|
+
import com.swmansion.enriched.markdown.spans.LineHeightSpan
|
|
15
|
+
import com.swmansion.enriched.markdown.spans.MarginBottomSpan
|
|
16
|
+
import android.text.style.LineHeightSpan as AndroidLineHeightSpan
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Constants
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Standard span flags for exclusive span boundaries.
|
|
24
|
+
* Spans with these flags do not expand when text is inserted at their boundaries.
|
|
25
|
+
*/
|
|
26
|
+
const val SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE = SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// TextPaint Extensions
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Applies a color to TextPaint while preserving priority colors (e.g., link color).
|
|
34
|
+
*/
|
|
35
|
+
fun TextPaint.applyColorPreserving(
|
|
36
|
+
color: Int,
|
|
37
|
+
vararg preserveColors: Int,
|
|
38
|
+
) {
|
|
39
|
+
if (this.color !in preserveColors) {
|
|
40
|
+
this.color = color
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private val typefaceCache = mutableMapOf<String, Typeface>()
|
|
45
|
+
private val fontWeightCache = mutableMapOf<String?, Int>()
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Applies fontFamily and fontWeight from BlockStyle to TextPaint.
|
|
49
|
+
* Uses caching to avoid expensive typeface creation on every call.
|
|
50
|
+
*/
|
|
51
|
+
fun TextPaint.applyBlockStyleFont(
|
|
52
|
+
blockStyle: BlockStyle,
|
|
53
|
+
context: Context,
|
|
54
|
+
) {
|
|
55
|
+
val cacheKey = "${blockStyle.fontFamily}|${blockStyle.fontWeight}"
|
|
56
|
+
|
|
57
|
+
val cachedTypeface = typefaceCache[cacheKey]
|
|
58
|
+
if (cachedTypeface != null) {
|
|
59
|
+
this.typeface = cachedTypeface
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
val fontWeight =
|
|
64
|
+
fontWeightCache.getOrPut(blockStyle.fontWeight) {
|
|
65
|
+
parseFontWeight(blockStyle.fontWeight)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Pass null as base typeface - this matches React Native Text behavior
|
|
69
|
+
// applyStyles will use ReactFontManager to load custom fonts from assets
|
|
70
|
+
val newTypeface =
|
|
71
|
+
applyStyles(
|
|
72
|
+
null, // Let applyStyles handle font loading from assets
|
|
73
|
+
ReactConstants.UNSET,
|
|
74
|
+
fontWeight,
|
|
75
|
+
blockStyle.fontFamily.takeIf { it.isNotEmpty() },
|
|
76
|
+
context.assets,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
typefaceCache[cacheKey] = newTypeface
|
|
80
|
+
this.typeface = newTypeface
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Paragraph/Node Utilities
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Determines if a paragraph contains only a single block image.
|
|
89
|
+
*/
|
|
90
|
+
fun MarkdownASTNode.containsBlockImage(): Boolean {
|
|
91
|
+
if (type != MarkdownASTNode.NodeType.Paragraph) return false
|
|
92
|
+
val firstChild = children.firstOrNull()
|
|
93
|
+
return firstChild != null && children.size == 1 && firstChild.type == MarkdownASTNode.NodeType.Image
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ============================================================================
|
|
97
|
+
// SpannableStringBuilder Extensions
|
|
98
|
+
// ============================================================================
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Determines if an image should be rendered inline (within text) or as a block element.
|
|
102
|
+
* An image is inline if it's not preceded by a line break or zero-width space.
|
|
103
|
+
*/
|
|
104
|
+
fun SpannableStringBuilder.isInlineImage(): Boolean {
|
|
105
|
+
if (isEmpty()) return false
|
|
106
|
+
val lastChar = last()
|
|
107
|
+
return lastChar != '\n' && lastChar != '\u200B'
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Span Creation Utilities
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
fun createLineHeightSpan(lineHeight: Float): AndroidLineHeightSpan = LineHeightSpan(lineHeight)
|
|
115
|
+
|
|
116
|
+
fun applyMarginTop(
|
|
117
|
+
builder: SpannableStringBuilder,
|
|
118
|
+
insertionPoint: Int,
|
|
119
|
+
marginTop: Float,
|
|
120
|
+
) {
|
|
121
|
+
if (marginTop <= 0) return
|
|
122
|
+
|
|
123
|
+
// Insert a newline character to act as a vertical spacer
|
|
124
|
+
builder.insert(insertionPoint, "\n")
|
|
125
|
+
|
|
126
|
+
// Apply MarginBottomSpan to the spacer character to create the gap before the content
|
|
127
|
+
builder.setSpan(
|
|
128
|
+
MarginBottomSpan(marginTop),
|
|
129
|
+
insertionPoint,
|
|
130
|
+
insertionPoint + 1,
|
|
131
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Applies marginBottom spacing to a block element.
|
|
137
|
+
* Appends a newline spacer and applies MarginBottomSpan to ONLY the spacer character.
|
|
138
|
+
*
|
|
139
|
+
* The span covers only the trailing newline to avoid overlapping with LineHeightSpan
|
|
140
|
+
* on content lines, which would cause incorrect spacing due to conflicting font metric
|
|
141
|
+
* modifications in chooseHeight().
|
|
142
|
+
*
|
|
143
|
+
* @param builder The SpannableStringBuilder to modify
|
|
144
|
+
* @param marginBottom The spacing value to apply after the block
|
|
145
|
+
*/
|
|
146
|
+
fun applyMarginBottom(
|
|
147
|
+
builder: SpannableStringBuilder,
|
|
148
|
+
marginBottom: Float,
|
|
149
|
+
) {
|
|
150
|
+
val spacerStart = builder.length
|
|
151
|
+
builder.append("\n")
|
|
152
|
+
// Always create a MarginBottomSpan, even when marginBottom = 0.
|
|
153
|
+
// This ensures removeTrailingMargin can correctly identify the LAST element's
|
|
154
|
+
// margin value. Without a span on the last element, it would pick up a previous
|
|
155
|
+
// element's span (e.g. blockquote with marginBottom: 16) and use that wrong value.
|
|
156
|
+
builder.setSpan(
|
|
157
|
+
MarginBottomSpan(marginBottom),
|
|
158
|
+
spacerStart,
|
|
159
|
+
builder.length,
|
|
160
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// ReadableMap Extensions
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
fun ReadableMap?.getBooleanOrDefault(
|
|
169
|
+
key: String,
|
|
170
|
+
default: Boolean,
|
|
171
|
+
): Boolean = if (this?.hasKey(key) == true) getBoolean(key) else default
|
|
172
|
+
|
|
173
|
+
fun ReadableMap?.getFloatOrDefault(
|
|
174
|
+
key: String,
|
|
175
|
+
default: Float,
|
|
176
|
+
): Float = if (this?.hasKey(key) == true) getDouble(key).toFloat() else default
|
|
177
|
+
|
|
178
|
+
fun ReadableMap?.getStringOrDefault(
|
|
179
|
+
key: String,
|
|
180
|
+
default: String,
|
|
181
|
+
): String = if (this?.hasKey(key) == true) getString(key) ?: default else default
|
|
182
|
+
|
|
183
|
+
fun ReadableMap?.getMapOrNull(key: String): ReadableMap? = if (this?.hasKey(key) == true) getMap(key) else null
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.13)
|
|
2
|
+
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
3
|
+
|
|
4
|
+
set(LIB_LITERAL EnrichedMarkdownTextSpec)
|
|
5
|
+
set(LIB_TARGET_NAME react_codegen_${LIB_LITERAL})
|
|
6
|
+
|
|
7
|
+
set(LIB_ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
|
8
|
+
set(LIB_ANDROID_GENERATED_JNI_DIR ${LIB_ANDROID_DIR}/generated/jni)
|
|
9
|
+
set(LIB_ANDROID_GENERATED_COMPONENTS_DIR ${LIB_ANDROID_GENERATED_JNI_DIR}/react/renderer/components/${LIB_LITERAL})
|
|
10
|
+
|
|
11
|
+
set(CPP_ROOT "${LIB_ANDROID_DIR}/../cpp")
|
|
12
|
+
set(ANDROID_CPP_DIR "${LIB_ANDROID_DIR}/src/main/cpp")
|
|
13
|
+
|
|
14
|
+
file(GLOB MD4C_SOURCES "${CPP_ROOT}/md4c/*.c")
|
|
15
|
+
file(GLOB PARSER_SOURCES "${CPP_ROOT}/parser/*.cpp")
|
|
16
|
+
|
|
17
|
+
# md4c is C code, build as separate static library with C flags
|
|
18
|
+
add_library(md4c_lib STATIC ${MD4C_SOURCES})
|
|
19
|
+
target_include_directories(md4c_lib PUBLIC ${CPP_ROOT}/md4c)
|
|
20
|
+
target_compile_definitions(md4c_lib PRIVATE MD4C_USE_UTF8=1)
|
|
21
|
+
set_target_properties(md4c_lib PROPERTIES
|
|
22
|
+
C_STANDARD 11
|
|
23
|
+
C_STANDARD_REQUIRED ON
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
file(GLOB LIB_CODEGEN_SRCS CONFIGURE_DEPENDS ${LIB_ANDROID_GENERATED_JNI_DIR}/*.cpp ${LIB_ANDROID_GENERATED_COMPONENTS_DIR}/*.cpp)
|
|
27
|
+
file(GLOB LIB_CUSTOM_JNI_SRCS CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/react/renderer/components/${LIB_LITERAL}/*.cpp)
|
|
28
|
+
|
|
29
|
+
add_library(
|
|
30
|
+
${LIB_TARGET_NAME}
|
|
31
|
+
SHARED
|
|
32
|
+
${LIB_CODEGEN_SRCS}
|
|
33
|
+
${LIB_CUSTOM_JNI_SRCS}
|
|
34
|
+
${PARSER_SOURCES}
|
|
35
|
+
${ANDROID_CPP_DIR}/jni-adapter.cpp
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
target_include_directories(
|
|
39
|
+
${LIB_TARGET_NAME}
|
|
40
|
+
PUBLIC
|
|
41
|
+
${CMAKE_CURRENT_SOURCE_DIR}
|
|
42
|
+
${CMAKE_CURRENT_SOURCE_DIR}/react/renderer/components/${LIB_LITERAL}
|
|
43
|
+
${LIB_ANDROID_GENERATED_JNI_DIR}
|
|
44
|
+
${LIB_ANDROID_GENERATED_COMPONENTS_DIR}
|
|
45
|
+
${CPP_ROOT}/md4c
|
|
46
|
+
${CPP_ROOT}/parser
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
target_compile_definitions(${LIB_TARGET_NAME} PRIVATE MD4C_USE_UTF8=1)
|
|
50
|
+
|
|
51
|
+
find_package(fbjni REQUIRED CONFIG)
|
|
52
|
+
find_package(ReactAndroid REQUIRED CONFIG)
|
|
53
|
+
find_library(LOG_LIB log)
|
|
54
|
+
|
|
55
|
+
target_link_libraries(
|
|
56
|
+
${LIB_TARGET_NAME}
|
|
57
|
+
${LOG_LIB}
|
|
58
|
+
md4c_lib
|
|
59
|
+
fbjni::fbjni
|
|
60
|
+
ReactAndroid::jsi
|
|
61
|
+
ReactAndroid::reactnative
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
target_include_directories(
|
|
65
|
+
${CMAKE_PROJECT_NAME}
|
|
66
|
+
PUBLIC
|
|
67
|
+
${CMAKE_CURRENT_SOURCE_DIR}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
target_compile_reactnative_options(${LIB_TARGET_NAME} PRIVATE)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This code was generated by
|
|
3
|
+
* [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be
|
|
6
|
+
* lost once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateModuleJniCpp.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#include "EnrichedMarkdownTextSpec.h"
|
|
12
|
+
|
|
13
|
+
namespace facebook::react {
|
|
14
|
+
|
|
15
|
+
std::shared_ptr<TurboModule> EnrichedMarkdownTextSpec_ModuleProvider(const std::string &moduleName,
|
|
16
|
+
const JavaTurboModule::InitParams ¶ms) {
|
|
17
|
+
|
|
18
|
+
return nullptr;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This code was generated by
|
|
3
|
+
* [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
|
|
4
|
+
*
|
|
5
|
+
* Do not edit this file as changes may cause incorrect behavior and will be
|
|
6
|
+
* lost once the code is regenerated.
|
|
7
|
+
*
|
|
8
|
+
* @generated by codegen project: GenerateModuleJniH.js
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
#pragma once
|
|
12
|
+
|
|
13
|
+
#include <ReactCommon/JavaTurboModule.h>
|
|
14
|
+
#include <ReactCommon/TurboModule.h>
|
|
15
|
+
#include <jsi/jsi.h>
|
|
16
|
+
|
|
17
|
+
#include <react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h>
|
|
18
|
+
|
|
19
|
+
namespace facebook::react {
|
|
20
|
+
|
|
21
|
+
JSI_EXPORT
|
|
22
|
+
std::shared_ptr<TurboModule> EnrichedMarkdownTextSpec_ModuleProvider(const std::string &moduleName,
|
|
23
|
+
const JavaTurboModule::InitParams ¶ms);
|
|
24
|
+
|
|
25
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "MarkdownTextMeasurementManager.h"
|
|
4
|
+
#include "MarkdownTextShadowNode.h"
|
|
5
|
+
|
|
6
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
7
|
+
|
|
8
|
+
namespace facebook::react {
|
|
9
|
+
|
|
10
|
+
class MarkdownTextComponentDescriptor final : public ConcreteComponentDescriptor<MarkdownTextShadowNode> {
|
|
11
|
+
public:
|
|
12
|
+
MarkdownTextComponentDescriptor(const ComponentDescriptorParameters ¶meters)
|
|
13
|
+
: ConcreteComponentDescriptor(parameters),
|
|
14
|
+
measurementsManager_(std::make_shared<MarkdownTextMeasurementManager>(contextContainer_)) {}
|
|
15
|
+
|
|
16
|
+
void adopt(ShadowNode &shadowNode) const override {
|
|
17
|
+
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
18
|
+
auto &markdownTextShadowNode = static_cast<MarkdownTextShadowNode &>(shadowNode);
|
|
19
|
+
|
|
20
|
+
// MarkdownTextShadowNode uses MarkdownTextMeasurementManager
|
|
21
|
+
// to provide measurements to Yoga.
|
|
22
|
+
markdownTextShadowNode.setMeasurementsManager(measurementsManager_);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
const std::shared_ptr<MarkdownTextMeasurementManager> measurementsManager_;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#include "MarkdownTextMeasurementManager.h"
|
|
2
|
+
#include "conversions.h"
|
|
3
|
+
|
|
4
|
+
#include <fbjni/fbjni.h>
|
|
5
|
+
#include <react/jni/ReadableNativeMap.h>
|
|
6
|
+
#include <react/renderer/core/conversions.h>
|
|
7
|
+
|
|
8
|
+
using namespace facebook::jni;
|
|
9
|
+
|
|
10
|
+
namespace facebook::react {
|
|
11
|
+
|
|
12
|
+
Size MarkdownTextMeasurementManager::measure(SurfaceId surfaceId, int viewTag, const EnrichedMarkdownTextProps &props,
|
|
13
|
+
LayoutConstraints layoutConstraints) const {
|
|
14
|
+
const jni::global_ref<jobject> &fabricUIManager = contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
|
|
15
|
+
|
|
16
|
+
static const auto measure =
|
|
17
|
+
facebook::jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
|
|
18
|
+
->getMethod<jlong(jint, jstring, ReadableMap::javaobject, ReadableMap::javaobject, ReadableMap::javaobject,
|
|
19
|
+
jfloat, jfloat, jfloat, jfloat)>("measure");
|
|
20
|
+
|
|
21
|
+
auto minimumSize = layoutConstraints.minimumSize;
|
|
22
|
+
auto maximumSize = layoutConstraints.maximumSize;
|
|
23
|
+
|
|
24
|
+
local_ref<JString> componentName = make_jstring("EnrichedMarkdownText");
|
|
25
|
+
|
|
26
|
+
// Prepare extraData map with viewTag
|
|
27
|
+
folly::dynamic extraData = folly::dynamic::object();
|
|
28
|
+
extraData["viewTag"] = viewTag;
|
|
29
|
+
local_ref<ReadableNativeMap::javaobject> extraDataRNM = ReadableNativeMap::newObjectCxxArgs(extraData);
|
|
30
|
+
local_ref<ReadableMap::javaobject> extraDataRM =
|
|
31
|
+
make_local(reinterpret_cast<ReadableMap::javaobject>(extraDataRNM.get()));
|
|
32
|
+
|
|
33
|
+
// Prepare layout metrics affecting props
|
|
34
|
+
auto serializedProps = toDynamic(props);
|
|
35
|
+
local_ref<ReadableNativeMap::javaobject> propsRNM = ReadableNativeMap::newObjectCxxArgs(serializedProps);
|
|
36
|
+
local_ref<ReadableMap::javaobject> propsRM = make_local(reinterpret_cast<ReadableMap::javaobject>(propsRNM.get()));
|
|
37
|
+
|
|
38
|
+
auto measurement = yogaMeassureToSize(measure(fabricUIManager, surfaceId, componentName.get(), extraDataRM.get(),
|
|
39
|
+
propsRM.get(), nullptr, minimumSize.width, maximumSize.width,
|
|
40
|
+
minimumSize.height, maximumSize.height));
|
|
41
|
+
|
|
42
|
+
return measurement;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/components/EnrichedMarkdownTextSpec/Props.h>
|
|
4
|
+
#include <react/renderer/core/LayoutConstraints.h>
|
|
5
|
+
#include <react/utils/ContextContainer.h>
|
|
6
|
+
|
|
7
|
+
namespace facebook::react {
|
|
8
|
+
|
|
9
|
+
class MarkdownTextMeasurementManager {
|
|
10
|
+
public:
|
|
11
|
+
MarkdownTextMeasurementManager(const std::shared_ptr<const ContextContainer> &contextContainer)
|
|
12
|
+
: contextContainer_(contextContainer) {}
|
|
13
|
+
|
|
14
|
+
Size measure(SurfaceId surfaceId, int viewTag, const EnrichedMarkdownTextProps &props,
|
|
15
|
+
LayoutConstraints layoutConstraints) const;
|
|
16
|
+
|
|
17
|
+
private:
|
|
18
|
+
const std::shared_ptr<const ContextContainer> contextContainer_;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#include "MarkdownTextShadowNode.h"
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/core/LayoutContext.h>
|
|
4
|
+
|
|
5
|
+
namespace facebook::react {
|
|
6
|
+
|
|
7
|
+
extern const char MarkdownTextComponentName[] = "EnrichedMarkdownText";
|
|
8
|
+
|
|
9
|
+
void MarkdownTextShadowNode::setMeasurementsManager(
|
|
10
|
+
const std::shared_ptr<MarkdownTextMeasurementManager> &measurementsManager) {
|
|
11
|
+
ensureUnsealed();
|
|
12
|
+
measurementsManager_ = measurementsManager;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Size MarkdownTextShadowNode::measureContent(const LayoutContext &layoutContext,
|
|
16
|
+
const LayoutConstraints &layoutConstraints) const {
|
|
17
|
+
return measurementsManager_->measure(getSurfaceId(), getTag(), getConcreteProps(), layoutConstraints);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "MarkdownTextMeasurementManager.h"
|
|
4
|
+
|
|
5
|
+
#include <react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h>
|
|
6
|
+
#include <react/renderer/components/EnrichedMarkdownTextSpec/Props.h>
|
|
7
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
8
|
+
|
|
9
|
+
namespace facebook::react {
|
|
10
|
+
|
|
11
|
+
JSI_EXPORT extern const char MarkdownTextComponentName[];
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* `ShadowNode` for <EnrichedMarkdownText> component.
|
|
15
|
+
*/
|
|
16
|
+
class MarkdownTextShadowNode final : public ConcreteViewShadowNode<MarkdownTextComponentName, EnrichedMarkdownTextProps,
|
|
17
|
+
EnrichedMarkdownTextEventEmitter> {
|
|
18
|
+
public:
|
|
19
|
+
using ConcreteViewShadowNode::ConcreteViewShadowNode;
|
|
20
|
+
|
|
21
|
+
static ShadowNodeTraits BaseTraits() {
|
|
22
|
+
auto traits = ConcreteViewShadowNode::BaseTraits();
|
|
23
|
+
traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
|
|
24
|
+
traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
|
|
25
|
+
return traits;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Associates a shared `MarkdownTextMeasurementManager` with the node.
|
|
29
|
+
void setMeasurementsManager(const std::shared_ptr<MarkdownTextMeasurementManager> &measurementsManager);
|
|
30
|
+
|
|
31
|
+
Size measureContent(const LayoutContext &layoutContext, const LayoutConstraints &layoutConstraints) const override;
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
std::shared_ptr<MarkdownTextMeasurementManager> measurementsManager_;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <folly/dynamic.h>
|
|
4
|
+
#include <react/renderer/components/EnrichedMarkdownTextSpec/Props.h>
|
|
5
|
+
#include <react/renderer/core/propsConversions.h>
|
|
6
|
+
|
|
7
|
+
namespace facebook::react {
|
|
8
|
+
|
|
9
|
+
#ifdef RN_SERIALIZABLE_STATE
|
|
10
|
+
inline folly::dynamic toDynamic(const EnrichedMarkdownTextProps &props) {
|
|
11
|
+
// Serialize measurement-affecting props
|
|
12
|
+
folly::dynamic serializedProps = folly::dynamic::object();
|
|
13
|
+
serializedProps["markdown"] = props.markdown;
|
|
14
|
+
serializedProps["markdownStyle"] = toDynamic(props.markdownStyle);
|
|
15
|
+
serializedProps["md4cFlags"] = toDynamic(props.md4cFlags);
|
|
16
|
+
serializedProps["allowTrailingMargin"] = props.allowTrailingMargin;
|
|
17
|
+
|
|
18
|
+
return serializedProps;
|
|
19
|
+
}
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
} // namespace facebook::react
|