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.
Files changed (226) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +551 -0
  3. package/ReactNativeEnrichedMarkdown.podspec +27 -0
  4. package/android/build.gradle +101 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +54 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +26 -0
  7. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  8. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  9. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +82 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1388 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  15. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
  16. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
  17. package/android/gradle.properties +5 -0
  18. package/android/src/main/AndroidManifest.xml +2 -0
  19. package/android/src/main/baseline-prof.txt +65 -0
  20. package/android/src/main/cpp/jni-adapter.cpp +220 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +270 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +15 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +173 -0
  24. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +17 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +385 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +279 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLongPressEvent.kt +23 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +31 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +62 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +84 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +104 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +36 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +16 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +27 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +70 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +68 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +16 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +29 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +59 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +76 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +103 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +80 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +109 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +86 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrikethroughRenderer.kt +27 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +27 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +30 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +45 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/UnderlineRenderer.kt +27 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +321 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +51 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrikethroughSpan.kt +12 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +11 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +51 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +54 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +33 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +23 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +57 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +33 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrikethroughStyle.kt +17 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +211 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +92 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TextAlignment.kt +32 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/styles/UnderlineStyle.kt +17 -0
  88. package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
  89. package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +827 -0
  90. package/android/src/main/java/com/swmansion/enriched/markdown/utils/LinkLongPressMovementMethod.kt +121 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +375 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
  93. package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +183 -0
  94. package/android/src/main/jni/CMakeLists.txt +70 -0
  95. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  96. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
  97. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  98. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  99. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  100. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +20 -0
  101. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +37 -0
  102. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +22 -0
  103. package/cpp/md4c/md4c.c +6492 -0
  104. package/cpp/md4c/md4c.h +402 -0
  105. package/cpp/parser/MD4CParser.cpp +327 -0
  106. package/cpp/parser/MD4CParser.hpp +27 -0
  107. package/cpp/parser/MarkdownASTNode.hpp +51 -0
  108. package/ios/EnrichedMarkdownText.h +18 -0
  109. package/ios/EnrichedMarkdownText.mm +1401 -0
  110. package/ios/attachments/EnrichedMarkdownImageAttachment.h +23 -0
  111. package/ios/attachments/EnrichedMarkdownImageAttachment.m +185 -0
  112. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  113. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  114. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  115. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  116. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
  117. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
  118. package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +82 -0
  119. package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1388 -0
  120. package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
  121. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  122. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  123. package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
  124. package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
  125. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  126. package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
  127. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
  128. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  129. package/ios/parser/MarkdownASTNode.h +35 -0
  130. package/ios/parser/MarkdownASTNode.m +32 -0
  131. package/ios/parser/MarkdownParser.h +17 -0
  132. package/ios/parser/MarkdownParser.mm +42 -0
  133. package/ios/parser/MarkdownParserBridge.mm +120 -0
  134. package/ios/renderer/AttributedRenderer.h +11 -0
  135. package/ios/renderer/AttributedRenderer.m +152 -0
  136. package/ios/renderer/BlockquoteRenderer.h +7 -0
  137. package/ios/renderer/BlockquoteRenderer.m +160 -0
  138. package/ios/renderer/CodeBlockRenderer.h +10 -0
  139. package/ios/renderer/CodeBlockRenderer.m +90 -0
  140. package/ios/renderer/CodeRenderer.h +10 -0
  141. package/ios/renderer/CodeRenderer.m +60 -0
  142. package/ios/renderer/EmphasisRenderer.h +6 -0
  143. package/ios/renderer/EmphasisRenderer.m +96 -0
  144. package/ios/renderer/HeadingRenderer.h +7 -0
  145. package/ios/renderer/HeadingRenderer.m +105 -0
  146. package/ios/renderer/ImageRenderer.h +12 -0
  147. package/ios/renderer/ImageRenderer.m +83 -0
  148. package/ios/renderer/LinkRenderer.h +7 -0
  149. package/ios/renderer/LinkRenderer.m +69 -0
  150. package/ios/renderer/ListItemRenderer.h +16 -0
  151. package/ios/renderer/ListItemRenderer.m +103 -0
  152. package/ios/renderer/ListRenderer.h +13 -0
  153. package/ios/renderer/ListRenderer.m +70 -0
  154. package/ios/renderer/NodeRenderer.h +8 -0
  155. package/ios/renderer/ParagraphRenderer.h +7 -0
  156. package/ios/renderer/ParagraphRenderer.m +80 -0
  157. package/ios/renderer/RenderContext.h +105 -0
  158. package/ios/renderer/RenderContext.m +312 -0
  159. package/ios/renderer/RendererFactory.h +12 -0
  160. package/ios/renderer/RendererFactory.m +116 -0
  161. package/ios/renderer/StrikethroughRenderer.h +6 -0
  162. package/ios/renderer/StrikethroughRenderer.m +40 -0
  163. package/ios/renderer/StrongRenderer.h +6 -0
  164. package/ios/renderer/StrongRenderer.m +83 -0
  165. package/ios/renderer/TextRenderer.h +6 -0
  166. package/ios/renderer/TextRenderer.m +16 -0
  167. package/ios/renderer/ThematicBreakRenderer.h +5 -0
  168. package/ios/renderer/ThematicBreakRenderer.m +53 -0
  169. package/ios/renderer/UnderlineRenderer.h +6 -0
  170. package/ios/renderer/UnderlineRenderer.m +39 -0
  171. package/ios/styles/StyleConfig.h +274 -0
  172. package/ios/styles/StyleConfig.mm +1806 -0
  173. package/ios/utils/AccessibilityInfo.h +35 -0
  174. package/ios/utils/AccessibilityInfo.m +24 -0
  175. package/ios/utils/BlockquoteBorder.h +20 -0
  176. package/ios/utils/BlockquoteBorder.m +92 -0
  177. package/ios/utils/CodeBackground.h +19 -0
  178. package/ios/utils/CodeBackground.m +191 -0
  179. package/ios/utils/CodeBlockBackground.h +17 -0
  180. package/ios/utils/CodeBlockBackground.m +82 -0
  181. package/ios/utils/EditMenuUtils.h +22 -0
  182. package/ios/utils/EditMenuUtils.m +118 -0
  183. package/ios/utils/FontUtils.h +25 -0
  184. package/ios/utils/FontUtils.m +27 -0
  185. package/ios/utils/HTMLGenerator.h +20 -0
  186. package/ios/utils/HTMLGenerator.m +793 -0
  187. package/ios/utils/LastElementUtils.h +53 -0
  188. package/ios/utils/ListMarkerDrawer.h +15 -0
  189. package/ios/utils/ListMarkerDrawer.m +127 -0
  190. package/ios/utils/MarkdownAccessibilityElementBuilder.h +45 -0
  191. package/ios/utils/MarkdownAccessibilityElementBuilder.m +323 -0
  192. package/ios/utils/MarkdownExtractor.h +17 -0
  193. package/ios/utils/MarkdownExtractor.m +308 -0
  194. package/ios/utils/ParagraphStyleUtils.h +21 -0
  195. package/ios/utils/ParagraphStyleUtils.m +111 -0
  196. package/ios/utils/PasteboardUtils.h +36 -0
  197. package/ios/utils/PasteboardUtils.m +134 -0
  198. package/ios/utils/RTFExportUtils.h +24 -0
  199. package/ios/utils/RTFExportUtils.m +297 -0
  200. package/ios/utils/RuntimeKeys.h +38 -0
  201. package/ios/utils/RuntimeKeys.m +11 -0
  202. package/ios/utils/TextViewLayoutManager.h +14 -0
  203. package/ios/utils/TextViewLayoutManager.mm +113 -0
  204. package/lib/module/EnrichedMarkdownText.js +65 -0
  205. package/lib/module/EnrichedMarkdownText.js.map +1 -0
  206. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +210 -0
  207. package/lib/module/index.js +4 -0
  208. package/lib/module/index.js.map +1 -0
  209. package/lib/module/normalizeMarkdownStyle.js +384 -0
  210. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  211. package/lib/module/package.json +1 -0
  212. package/lib/typescript/package.json +1 -0
  213. package/lib/typescript/src/EnrichedMarkdownText.d.ts +183 -0
  214. package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
  215. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +185 -0
  216. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  217. package/lib/typescript/src/index.d.ts +4 -0
  218. package/lib/typescript/src/index.d.ts.map +1 -0
  219. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
  220. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  221. package/package.json +186 -1
  222. package/react-native.config.js +13 -0
  223. package/src/EnrichedMarkdownText.tsx +280 -0
  224. package/src/EnrichedMarkdownTextNativeComponent.ts +210 -0
  225. package/src/index.tsx +10 -0
  226. package/src/normalizeMarkdownStyle.ts +423 -0
@@ -0,0 +1,69 @@
1
+ package com.swmansion.enriched.markdown.spans
2
+
3
+ import android.content.Context
4
+ import android.graphics.Canvas
5
+ import android.graphics.Paint
6
+ import android.text.Layout
7
+ import com.swmansion.enriched.markdown.renderer.BlockStyle
8
+ import com.swmansion.enriched.markdown.renderer.SpanStyleCache
9
+ import com.swmansion.enriched.markdown.styles.ListStyle
10
+
11
+ class UnorderedListSpan(
12
+ private val listStyle: ListStyle,
13
+ depth: Int,
14
+ context: Context,
15
+ styleCache: SpanStyleCache,
16
+ ) : BaseListSpan(
17
+ depth = depth,
18
+ context = context,
19
+ styleCache = styleCache,
20
+ blockStyle =
21
+ BlockStyle(
22
+ fontSize = listStyle.fontSize,
23
+ fontFamily = listStyle.fontFamily,
24
+ fontWeight = listStyle.fontWeight,
25
+ color = listStyle.color,
26
+ ),
27
+ marginLeft = listStyle.marginLeft,
28
+ gapWidth = listStyle.gapWidth,
29
+ ) {
30
+ companion object {
31
+ private val sharedBulletPaint =
32
+ Paint(Paint.ANTI_ALIAS_FLAG).apply {
33
+ style = Paint.Style.FILL
34
+ }
35
+ }
36
+
37
+ private val radius: Float = listStyle.bulletSize / 2f
38
+
39
+ private fun configureBulletPaint(): Paint =
40
+ sharedBulletPaint.apply {
41
+ color = listStyle.bulletColor
42
+ }
43
+
44
+ override fun getMarkerWidth(): Float = radius
45
+
46
+ override fun drawMarker(
47
+ c: Canvas,
48
+ p: Paint,
49
+ x: Int,
50
+ dir: Int,
51
+ top: Int,
52
+ baseline: Int,
53
+ bottom: Int,
54
+ layout: Layout?,
55
+ start: Int,
56
+ ) {
57
+ val bulletPaint = configureBulletPaint()
58
+
59
+ // Calculate bullet position based on depth
60
+ // depth 0: radius, depth 1: marginLeft + radius, etc.
61
+ val bulletX = (depth * marginLeft + radius) * dir
62
+
63
+ // Vertical centering based on font metrics
64
+ val fm = p.fontMetrics
65
+ val bulletY = baseline + (fm.ascent + fm.descent) / 2f
66
+
67
+ c.drawCircle(bulletX, bulletY, radius, bulletPaint)
68
+ }
69
+ }
@@ -0,0 +1,11 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ interface BaseBlockStyle {
4
+ val fontSize: Float
5
+ val fontFamily: String
6
+ val fontWeight: String
7
+ val color: Int
8
+ val marginTop: Float
9
+ val marginBottom: Float
10
+ val lineHeight: Float
11
+ }
@@ -0,0 +1,51 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class BlockquoteStyle(
6
+ override val fontSize: Float,
7
+ override val fontFamily: String,
8
+ override val fontWeight: String,
9
+ override val color: Int,
10
+ override val marginTop: Float,
11
+ override val marginBottom: Float,
12
+ override val lineHeight: Float,
13
+ val borderColor: Int,
14
+ val borderWidth: Float,
15
+ val gapWidth: Float,
16
+ val backgroundColor: Int?,
17
+ ) : BaseBlockStyle {
18
+ companion object {
19
+ fun fromReadableMap(
20
+ map: ReadableMap,
21
+ parser: StyleParser,
22
+ ): BlockquoteStyle {
23
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
24
+ val fontFamily = parser.parseString(map, "fontFamily")
25
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
26
+ val color = parser.parseColor(map, "color")
27
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
28
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
29
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
30
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
31
+ val borderColor = parser.parseColor(map, "borderColor")
32
+ val borderWidth = parser.toPixelFromDIP(map.getDouble("borderWidth").toFloat())
33
+ val gapWidth = parser.toPixelFromDIP(map.getDouble("gapWidth").toFloat())
34
+ val backgroundColor = parser.parseOptionalColor(map, "backgroundColor")
35
+
36
+ return BlockquoteStyle(
37
+ fontSize,
38
+ fontFamily,
39
+ fontWeight,
40
+ color,
41
+ marginTop,
42
+ marginBottom,
43
+ lineHeight,
44
+ borderColor,
45
+ borderWidth,
46
+ gapWidth,
47
+ backgroundColor,
48
+ )
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,54 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class CodeBlockStyle(
6
+ override val fontSize: Float,
7
+ override val fontFamily: String,
8
+ override val fontWeight: String,
9
+ override val color: Int,
10
+ override val marginTop: Float,
11
+ override val marginBottom: Float,
12
+ override val lineHeight: Float,
13
+ val backgroundColor: Int,
14
+ val borderColor: Int,
15
+ val borderRadius: Float,
16
+ val borderWidth: Float,
17
+ val padding: Float,
18
+ ) : BaseBlockStyle {
19
+ companion object {
20
+ fun fromReadableMap(
21
+ map: ReadableMap,
22
+ parser: StyleParser,
23
+ ): CodeBlockStyle {
24
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
25
+ val fontFamily = parser.parseString(map, "fontFamily")
26
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
27
+ val color = parser.parseColor(map, "color")
28
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
29
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
30
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
31
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
32
+ val backgroundColor = parser.parseColor(map, "backgroundColor")
33
+ val borderColor = parser.parseColor(map, "borderColor")
34
+ val borderRadius = parser.toPixelFromDIP(map.getDouble("borderRadius").toFloat())
35
+ val borderWidth = parser.toPixelFromDIP(map.getDouble("borderWidth").toFloat())
36
+ val padding = parser.toPixelFromDIP(map.getDouble("padding").toFloat())
37
+
38
+ return CodeBlockStyle(
39
+ fontSize,
40
+ fontFamily,
41
+ fontWeight,
42
+ color,
43
+ marginTop,
44
+ marginBottom,
45
+ lineHeight,
46
+ backgroundColor,
47
+ borderColor,
48
+ borderRadius,
49
+ borderWidth,
50
+ padding,
51
+ )
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,21 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class CodeStyle(
6
+ val color: Int,
7
+ val backgroundColor: Int,
8
+ val borderColor: Int,
9
+ ) {
10
+ companion object {
11
+ fun fromReadableMap(
12
+ map: ReadableMap,
13
+ parser: StyleParser,
14
+ ): CodeStyle {
15
+ val color = parser.parseColor(map, "color")
16
+ val backgroundColor = parser.parseColor(map, "backgroundColor")
17
+ val borderColor = parser.parseColor(map, "borderColor")
18
+ return CodeStyle(color, backgroundColor, borderColor)
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,17 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class EmphasisStyle(
6
+ val color: Int?,
7
+ ) {
8
+ companion object {
9
+ fun fromReadableMap(
10
+ map: ReadableMap,
11
+ parser: StyleParser,
12
+ ): EmphasisStyle {
13
+ val color = parser.parseOptionalColor(map, "color")
14
+ return EmphasisStyle(color)
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class HeadingStyle(
6
+ override val fontSize: Float,
7
+ override val fontFamily: String,
8
+ override val fontWeight: String,
9
+ override val color: Int,
10
+ override val marginTop: Float,
11
+ override val marginBottom: Float,
12
+ override val lineHeight: Float,
13
+ val textAlign: TextAlignment,
14
+ ) : BaseBlockStyle {
15
+ companion object {
16
+ fun fromReadableMap(
17
+ map: ReadableMap,
18
+ parser: StyleParser,
19
+ ): HeadingStyle {
20
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
21
+ val fontFamily = parser.parseString(map, "fontFamily")
22
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
23
+ val color = parser.parseColor(map, "color")
24
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
25
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
26
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
27
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
28
+ val textAlign = parser.parseTextAlign(map, "textAlign")
29
+
30
+ return HeadingStyle(fontSize, fontFamily, fontWeight, color, marginTop, marginBottom, lineHeight, textAlign)
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,23 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class ImageStyle(
6
+ val height: Float,
7
+ val borderRadius: Float,
8
+ val marginTop: Float,
9
+ val marginBottom: Float,
10
+ ) {
11
+ companion object {
12
+ fun fromReadableMap(
13
+ map: ReadableMap,
14
+ parser: StyleParser,
15
+ ): ImageStyle {
16
+ val height = parser.toPixelFromDIP(map.getDouble("height").toFloat())
17
+ val borderRadius = parser.toPixelFromDIP(map.getDouble("borderRadius").toFloat())
18
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
19
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
20
+ return ImageStyle(height, borderRadius, marginTop, marginBottom)
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,17 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class InlineImageStyle(
6
+ val size: Float,
7
+ ) {
8
+ companion object {
9
+ fun fromReadableMap(
10
+ map: ReadableMap,
11
+ parser: StyleParser,
12
+ ): InlineImageStyle {
13
+ val size = parser.toPixelFromDIP(map.getDouble("size").toFloat())
14
+ return InlineImageStyle(size)
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,19 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class LinkStyle(
6
+ val color: Int,
7
+ val underline: Boolean,
8
+ ) {
9
+ companion object {
10
+ fun fromReadableMap(
11
+ map: ReadableMap,
12
+ parser: StyleParser,
13
+ ): LinkStyle {
14
+ val color = parser.parseColor(map, "color")
15
+ val underline = map.getBoolean("underline")
16
+ return LinkStyle(color, underline)
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,57 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class ListStyle(
6
+ override val fontSize: Float,
7
+ override val fontFamily: String,
8
+ override val fontWeight: String,
9
+ override val color: Int,
10
+ override val marginTop: Float,
11
+ override val marginBottom: Float,
12
+ override val lineHeight: Float,
13
+ val bulletColor: Int,
14
+ val bulletSize: Float,
15
+ val markerColor: Int,
16
+ val markerFontWeight: String,
17
+ val gapWidth: Float,
18
+ val marginLeft: Float,
19
+ ) : BaseBlockStyle {
20
+ companion object {
21
+ fun fromReadableMap(
22
+ map: ReadableMap,
23
+ parser: StyleParser,
24
+ ): ListStyle {
25
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
26
+ val fontFamily = parser.parseString(map, "fontFamily")
27
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
28
+ val color = parser.parseColor(map, "color")
29
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
30
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
31
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
32
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
33
+ val bulletColor = parser.parseColor(map, "bulletColor")
34
+ val bulletSize = parser.toPixelFromDIP(map.getDouble("bulletSize").toFloat())
35
+ val markerColor = parser.parseColor(map, "markerColor")
36
+ val markerFontWeight = parser.parseString(map, "markerFontWeight", "normal")
37
+ val gapWidth = parser.toPixelFromDIP(map.getDouble("gapWidth").toFloat())
38
+ val marginLeft = parser.toPixelFromDIP(map.getDouble("marginLeft").toFloat())
39
+
40
+ return ListStyle(
41
+ fontSize,
42
+ fontFamily,
43
+ fontWeight,
44
+ color,
45
+ marginTop,
46
+ marginBottom,
47
+ lineHeight,
48
+ bulletColor,
49
+ bulletSize,
50
+ markerColor,
51
+ markerFontWeight,
52
+ gapWidth,
53
+ marginLeft,
54
+ )
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,33 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class ParagraphStyle(
6
+ override val fontSize: Float,
7
+ override val fontFamily: String,
8
+ override val fontWeight: String,
9
+ override val color: Int,
10
+ override val marginTop: Float,
11
+ override val marginBottom: Float,
12
+ override val lineHeight: Float,
13
+ val textAlign: TextAlignment,
14
+ ) : BaseBlockStyle {
15
+ companion object {
16
+ fun fromReadableMap(
17
+ map: ReadableMap,
18
+ parser: StyleParser,
19
+ ): ParagraphStyle {
20
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
21
+ val fontFamily = parser.parseString(map, "fontFamily")
22
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
23
+ val color = parser.parseColor(map, "color")
24
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
25
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
26
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
27
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
28
+ val textAlign = parser.parseTextAlign(map, "textAlign")
29
+
30
+ return ParagraphStyle(fontSize, fontFamily, fontWeight, color, marginTop, marginBottom, lineHeight, textAlign)
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,17 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class StrikethroughStyle(
6
+ val color: Int,
7
+ ) {
8
+ companion object {
9
+ fun fromReadableMap(
10
+ map: ReadableMap,
11
+ parser: StyleParser,
12
+ ): StrikethroughStyle {
13
+ val color = parser.parseColor(map, "color")
14
+ return StrikethroughStyle(color)
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class StrongStyle(
6
+ val color: Int?,
7
+ ) {
8
+ companion object {
9
+ fun fromReadableMap(
10
+ map: ReadableMap,
11
+ parser: StyleParser,
12
+ ): StrongStyle {
13
+ val color = parser.parseOptionalColor(map, "color")
14
+ return StrongStyle(color)
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,211 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import android.content.Context
4
+ import android.content.res.AssetManager
5
+ import android.graphics.Typeface
6
+ import com.facebook.react.bridge.ReadableMap
7
+ import com.facebook.react.common.ReactConstants
8
+ import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
9
+ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
10
+
11
+ /**
12
+ * Main style configuration class that parses and caches all markdown element styles.
13
+ * Uses lazy initialization to defer parsing until styles are actually needed,
14
+ * improving startup time for documents that don't use all markdown features.
15
+ */
16
+ class StyleConfig(
17
+ private val style: ReadableMap,
18
+ context: Context,
19
+ allowFontScaling: Boolean,
20
+ maxFontSizeMultiplier: Float,
21
+ ) {
22
+ private val styleParser = StyleParser(context, allowFontScaling, maxFontSizeMultiplier)
23
+ private val assets: AssetManager = context.assets
24
+
25
+ val paragraphStyle: ParagraphStyle by lazy {
26
+ val map =
27
+ requireNotNull(style.getMap("paragraph")) {
28
+ "Paragraph style not found. JS should always provide defaults."
29
+ }
30
+ ParagraphStyle.fromReadableMap(map, styleParser)
31
+ }
32
+
33
+ val headingStyles: Array<HeadingStyle?> by lazy {
34
+ Array(7) { index ->
35
+ if (index == 0) {
36
+ null
37
+ } else {
38
+ val levelKey = "h$index"
39
+ val map =
40
+ requireNotNull(style.getMap(levelKey)) {
41
+ "Style for $levelKey not found. JS should always provide defaults."
42
+ }
43
+ HeadingStyle.fromReadableMap(map, styleParser)
44
+ }
45
+ }
46
+ }
47
+
48
+ // Cache typefaces for heading levels (1-6) - lazily initialized after headingStyles
49
+ // Uses React Native's applyStyles to properly load custom fonts from assets
50
+ val headingTypefaces: Array<Typeface?> by lazy {
51
+ Array(7) { level ->
52
+ if (level == 0) {
53
+ null
54
+ } else {
55
+ val headingStyle = headingStyles[level]
56
+ val fontFamily = headingStyle?.fontFamily?.takeIf { it.isNotEmpty() }
57
+ val fontWeight = parseFontWeight(headingStyle?.fontWeight)
58
+
59
+ if (fontFamily != null) {
60
+ // Use applyStyles with null base typeface to load from assets via ReactFontManager
61
+ applyStyles(null, ReactConstants.UNSET, fontWeight, fontFamily, assets)
62
+ } else {
63
+ null
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ val linkStyle: LinkStyle by lazy {
70
+ val map =
71
+ requireNotNull(style.getMap("link")) {
72
+ "Link style not found. JS should always provide defaults."
73
+ }
74
+ LinkStyle.fromReadableMap(map, styleParser)
75
+ }
76
+
77
+ val strongStyle: StrongStyle by lazy {
78
+ val map =
79
+ requireNotNull(style.getMap("strong")) {
80
+ "Strong style not found. JS should always provide defaults."
81
+ }
82
+ StrongStyle.fromReadableMap(map, styleParser)
83
+ }
84
+
85
+ val emphasisStyle: EmphasisStyle by lazy {
86
+ val map =
87
+ requireNotNull(style.getMap("em")) {
88
+ "Emphasis style not found. JS should always provide defaults."
89
+ }
90
+ EmphasisStyle.fromReadableMap(map, styleParser)
91
+ }
92
+
93
+ val strikethroughStyle: StrikethroughStyle by lazy {
94
+ val map =
95
+ requireNotNull(style.getMap("strikethrough")) {
96
+ "Strikethrough style not found. JS should always provide defaults."
97
+ }
98
+ StrikethroughStyle.fromReadableMap(map, styleParser)
99
+ }
100
+
101
+ val underlineStyle: UnderlineStyle by lazy {
102
+ val map =
103
+ requireNotNull(style.getMap("underline")) {
104
+ "Underline style not found. JS should always provide defaults."
105
+ }
106
+ UnderlineStyle.fromReadableMap(map, styleParser)
107
+ }
108
+
109
+ val codeStyle: CodeStyle by lazy {
110
+ val map =
111
+ requireNotNull(style.getMap("code")) {
112
+ "Code style not found. JS should always provide defaults."
113
+ }
114
+ CodeStyle.fromReadableMap(map, styleParser)
115
+ }
116
+
117
+ val imageStyle: ImageStyle by lazy {
118
+ val map =
119
+ requireNotNull(style.getMap("image")) {
120
+ "Image style not found. JS should always provide defaults."
121
+ }
122
+ ImageStyle.fromReadableMap(map, styleParser)
123
+ }
124
+
125
+ val inlineImageStyle: InlineImageStyle by lazy {
126
+ val map =
127
+ requireNotNull(style.getMap("inlineImage")) {
128
+ "InlineImage style not found. JS should always provide defaults."
129
+ }
130
+ InlineImageStyle.fromReadableMap(map, styleParser)
131
+ }
132
+
133
+ val blockquoteStyle: BlockquoteStyle by lazy {
134
+ val map =
135
+ requireNotNull(style.getMap("blockquote")) {
136
+ "Blockquote style not found. JS should always provide defaults."
137
+ }
138
+ BlockquoteStyle.fromReadableMap(map, styleParser)
139
+ }
140
+
141
+ val listStyle: ListStyle by lazy {
142
+ val map =
143
+ requireNotNull(style.getMap("list")) {
144
+ "List style not found. JS should always provide defaults."
145
+ }
146
+ ListStyle.fromReadableMap(map, styleParser)
147
+ }
148
+
149
+ val codeBlockStyle: CodeBlockStyle by lazy {
150
+ val map =
151
+ requireNotNull(style.getMap("codeBlock")) {
152
+ "CodeBlock style not found. JS should always provide defaults."
153
+ }
154
+ CodeBlockStyle.fromReadableMap(map, styleParser)
155
+ }
156
+
157
+ val thematicBreakStyle: ThematicBreakStyle by lazy {
158
+ val map =
159
+ requireNotNull(style.getMap("thematicBreak")) {
160
+ "ThematicBreak style not found. JS should always provide defaults."
161
+ }
162
+ ThematicBreakStyle.fromReadableMap(map, styleParser)
163
+ }
164
+
165
+ /**
166
+ * Returns true if any paragraph or heading style uses justify alignment.
167
+ * Used to enable justification mode on the TextView (API 26+).
168
+ */
169
+ val needsJustify: Boolean by lazy {
170
+ paragraphStyle.textAlign.needsJustify ||
171
+ headingStyles.filterNotNull().any { it.textAlign.needsJustify }
172
+ }
173
+
174
+ override fun equals(other: Any?): Boolean {
175
+ if (this === other) return true
176
+ if (other !is StyleConfig) return false
177
+
178
+ return paragraphStyle == other.paragraphStyle &&
179
+ headingStyles.contentEquals(other.headingStyles) &&
180
+ linkStyle == other.linkStyle &&
181
+ strongStyle == other.strongStyle &&
182
+ emphasisStyle == other.emphasisStyle &&
183
+ strikethroughStyle == other.strikethroughStyle &&
184
+ underlineStyle == other.underlineStyle &&
185
+ codeStyle == other.codeStyle &&
186
+ imageStyle == other.imageStyle &&
187
+ inlineImageStyle == other.inlineImageStyle &&
188
+ blockquoteStyle == other.blockquoteStyle &&
189
+ listStyle == other.listStyle &&
190
+ codeBlockStyle == other.codeBlockStyle &&
191
+ thematicBreakStyle == other.thematicBreakStyle
192
+ }
193
+
194
+ override fun hashCode(): Int {
195
+ var result = paragraphStyle.hashCode()
196
+ result = 31 * result + headingStyles.contentHashCode()
197
+ result = 31 * result + linkStyle.hashCode()
198
+ result = 31 * result + strongStyle.hashCode()
199
+ result = 31 * result + emphasisStyle.hashCode()
200
+ result = 31 * result + strikethroughStyle.hashCode()
201
+ result = 31 * result + underlineStyle.hashCode()
202
+ result = 31 * result + codeStyle.hashCode()
203
+ result = 31 * result + imageStyle.hashCode()
204
+ result = 31 * result + inlineImageStyle.hashCode()
205
+ result = 31 * result + blockquoteStyle.hashCode()
206
+ result = 31 * result + listStyle.hashCode()
207
+ result = 31 * result + codeBlockStyle.hashCode()
208
+ result = 31 * result + thematicBreakStyle.hashCode()
209
+ return result
210
+ }
211
+ }