react-native-enriched-markdown 0.1.0 → 0.1.1

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 (211) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +479 -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 +39 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +21 -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 +24 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1164 -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 +203 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +153 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +30 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +119 -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 +165 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +29 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +48 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +89 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +105 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +35 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +15 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +26 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +54 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +52 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +15 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +28 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +58 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +69 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +99 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +66 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +95 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +85 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +26 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +29 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +44 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +320 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +36 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +10 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +48 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +51 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +29 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +21 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +54 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +29 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +180 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +75 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +809 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +365 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +181 -0
  85. package/android/src/main/jni/CMakeLists.txt +82 -0
  86. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  87. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
  88. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  89. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  90. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  91. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +33 -0
  92. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +49 -0
  93. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  94. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +25 -0
  95. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +19 -0
  96. package/cpp/md4c/md4c.c +6492 -0
  97. package/cpp/md4c/md4c.h +402 -0
  98. package/cpp/parser/MD4CParser.cpp +314 -0
  99. package/cpp/parser/MD4CParser.hpp +23 -0
  100. package/cpp/parser/MarkdownASTNode.hpp +49 -0
  101. package/ios/EnrichedMarkdownText.h +18 -0
  102. package/ios/EnrichedMarkdownText.mm +1074 -0
  103. package/ios/attachments/ImageAttachment.h +23 -0
  104. package/ios/attachments/ImageAttachment.m +185 -0
  105. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  106. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  107. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  108. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  109. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +24 -0
  110. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  111. package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  112. package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1164 -0
  113. package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
  114. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  115. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  116. package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
  117. package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
  118. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  119. package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
  120. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
  121. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  122. package/ios/parser/MarkdownASTNode.h +33 -0
  123. package/ios/parser/MarkdownASTNode.m +32 -0
  124. package/ios/parser/MarkdownParser.h +8 -0
  125. package/ios/parser/MarkdownParser.mm +13 -0
  126. package/ios/parser/MarkdownParserBridge.mm +110 -0
  127. package/ios/renderer/AttributedRenderer.h +9 -0
  128. package/ios/renderer/AttributedRenderer.m +119 -0
  129. package/ios/renderer/BlockquoteRenderer.h +7 -0
  130. package/ios/renderer/BlockquoteRenderer.m +159 -0
  131. package/ios/renderer/CodeBlockRenderer.h +10 -0
  132. package/ios/renderer/CodeBlockRenderer.m +89 -0
  133. package/ios/renderer/CodeRenderer.h +10 -0
  134. package/ios/renderer/CodeRenderer.m +60 -0
  135. package/ios/renderer/EmphasisRenderer.h +6 -0
  136. package/ios/renderer/EmphasisRenderer.m +96 -0
  137. package/ios/renderer/HeadingRenderer.h +7 -0
  138. package/ios/renderer/HeadingRenderer.m +98 -0
  139. package/ios/renderer/ImageRenderer.h +12 -0
  140. package/ios/renderer/ImageRenderer.m +62 -0
  141. package/ios/renderer/LinkRenderer.h +7 -0
  142. package/ios/renderer/LinkRenderer.m +69 -0
  143. package/ios/renderer/ListItemRenderer.h +16 -0
  144. package/ios/renderer/ListItemRenderer.m +91 -0
  145. package/ios/renderer/ListRenderer.h +13 -0
  146. package/ios/renderer/ListRenderer.m +67 -0
  147. package/ios/renderer/NodeRenderer.h +8 -0
  148. package/ios/renderer/ParagraphRenderer.h +7 -0
  149. package/ios/renderer/ParagraphRenderer.m +69 -0
  150. package/ios/renderer/RenderContext.h +88 -0
  151. package/ios/renderer/RenderContext.m +248 -0
  152. package/ios/renderer/RendererFactory.h +12 -0
  153. package/ios/renderer/RendererFactory.m +110 -0
  154. package/ios/renderer/StrongRenderer.h +6 -0
  155. package/ios/renderer/StrongRenderer.m +83 -0
  156. package/ios/renderer/TextRenderer.h +6 -0
  157. package/ios/renderer/TextRenderer.m +16 -0
  158. package/ios/renderer/ThematicBreakRenderer.h +5 -0
  159. package/ios/renderer/ThematicBreakRenderer.m +53 -0
  160. package/ios/styles/StyleConfig.h +228 -0
  161. package/ios/styles/StyleConfig.mm +1467 -0
  162. package/ios/utils/BlockquoteBorder.h +20 -0
  163. package/ios/utils/BlockquoteBorder.m +92 -0
  164. package/ios/utils/CodeBackground.h +19 -0
  165. package/ios/utils/CodeBackground.m +191 -0
  166. package/ios/utils/CodeBlockBackground.h +17 -0
  167. package/ios/utils/CodeBlockBackground.m +87 -0
  168. package/ios/utils/EditMenuUtils.h +22 -0
  169. package/ios/utils/EditMenuUtils.m +118 -0
  170. package/ios/utils/FontUtils.h +20 -0
  171. package/ios/utils/FontUtils.m +13 -0
  172. package/ios/utils/HTMLGenerator.h +20 -0
  173. package/ios/utils/HTMLGenerator.m +779 -0
  174. package/ios/utils/LastElementUtils.h +53 -0
  175. package/ios/utils/ListMarkerDrawer.h +15 -0
  176. package/ios/utils/ListMarkerDrawer.m +127 -0
  177. package/ios/utils/MarkdownExtractor.h +17 -0
  178. package/ios/utils/MarkdownExtractor.m +295 -0
  179. package/ios/utils/ParagraphStyleUtils.h +13 -0
  180. package/ios/utils/ParagraphStyleUtils.m +56 -0
  181. package/ios/utils/PasteboardUtils.h +36 -0
  182. package/ios/utils/PasteboardUtils.m +134 -0
  183. package/ios/utils/RTFExportUtils.h +24 -0
  184. package/ios/utils/RTFExportUtils.m +297 -0
  185. package/ios/utils/RuntimeKeys.h +38 -0
  186. package/ios/utils/RuntimeKeys.m +11 -0
  187. package/ios/utils/TextViewLayoutManager.h +14 -0
  188. package/ios/utils/TextViewLayoutManager.mm +113 -0
  189. package/lib/module/EnrichedMarkdownText.js +34 -0
  190. package/lib/module/EnrichedMarkdownText.js.map +1 -0
  191. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +130 -0
  192. package/lib/module/index.js +5 -0
  193. package/lib/module/index.js.map +1 -0
  194. package/lib/module/normalizeMarkdownStyle.js +340 -0
  195. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  196. package/lib/module/package.json +1 -0
  197. package/lib/typescript/package.json +1 -0
  198. package/lib/typescript/src/EnrichedMarkdownText.d.ts +101 -0
  199. package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
  200. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +111 -0
  201. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  202. package/lib/typescript/src/index.d.ts +5 -0
  203. package/lib/typescript/src/index.d.ts.map +1 -0
  204. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
  205. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  206. package/package.json +186 -1
  207. package/react-native.config.js +13 -0
  208. package/src/EnrichedMarkdownText.tsx +152 -0
  209. package/src/EnrichedMarkdownTextNativeComponent.ts +130 -0
  210. package/src/index.tsx +7 -0
  211. package/src/normalizeMarkdownStyle.ts +377 -0
@@ -0,0 +1,29 @@
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 marginBottom: Float,
11
+ override val lineHeight: Float,
12
+ ) : BaseBlockStyle {
13
+ companion object {
14
+ fun fromReadableMap(
15
+ map: ReadableMap,
16
+ parser: StyleParser,
17
+ ): ParagraphStyle {
18
+ val fontSize = parser.toPixelFromSP(map.getDouble("fontSize").toFloat())
19
+ val fontFamily = parser.parseString(map, "fontFamily")
20
+ val fontWeight = parser.parseString(map, "fontWeight", "normal")
21
+ val color = parser.parseColor(map, "color")
22
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
23
+ val lineHeightRaw = map.getDouble("lineHeight").toFloat()
24
+ val lineHeight = parser.toPixelFromSP(lineHeightRaw)
25
+
26
+ return ParagraphStyle(fontSize, fontFamily, fontWeight, color, marginBottom, lineHeight)
27
+ }
28
+ }
29
+ }
@@ -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,180 @@
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
+ ) {
20
+ private val styleParser = StyleParser(context)
21
+ private val assets: AssetManager = context.assets
22
+
23
+ val paragraphStyle: ParagraphStyle by lazy {
24
+ val map =
25
+ requireNotNull(style.getMap("paragraph")) {
26
+ "Paragraph style not found. JS should always provide defaults."
27
+ }
28
+ ParagraphStyle.fromReadableMap(map, styleParser)
29
+ }
30
+
31
+ val headingStyles: Array<HeadingStyle?> by lazy {
32
+ Array(7) { index ->
33
+ if (index == 0) {
34
+ null
35
+ } else {
36
+ val levelKey = "h$index"
37
+ val map =
38
+ requireNotNull(style.getMap(levelKey)) {
39
+ "Style for $levelKey not found. JS should always provide defaults."
40
+ }
41
+ HeadingStyle.fromReadableMap(map, styleParser)
42
+ }
43
+ }
44
+ }
45
+
46
+ // Cache typefaces for heading levels (1-6) - lazily initialized after headingStyles
47
+ // Uses React Native's applyStyles to properly load custom fonts from assets
48
+ val headingTypefaces: Array<Typeface?> by lazy {
49
+ Array(7) { level ->
50
+ if (level == 0) {
51
+ null
52
+ } else {
53
+ val headingStyle = headingStyles[level]
54
+ val fontFamily = headingStyle?.fontFamily?.takeIf { it.isNotEmpty() }
55
+ val fontWeight = parseFontWeight(headingStyle?.fontWeight)
56
+
57
+ if (fontFamily != null) {
58
+ // Use applyStyles with null base typeface to load from assets via ReactFontManager
59
+ applyStyles(null, ReactConstants.UNSET, fontWeight, fontFamily, assets)
60
+ } else {
61
+ null
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ val linkStyle: LinkStyle by lazy {
68
+ val map =
69
+ requireNotNull(style.getMap("link")) {
70
+ "Link style not found. JS should always provide defaults."
71
+ }
72
+ LinkStyle.fromReadableMap(map, styleParser)
73
+ }
74
+
75
+ val strongStyle: StrongStyle by lazy {
76
+ val map =
77
+ requireNotNull(style.getMap("strong")) {
78
+ "Strong style not found. JS should always provide defaults."
79
+ }
80
+ StrongStyle.fromReadableMap(map, styleParser)
81
+ }
82
+
83
+ val emphasisStyle: EmphasisStyle by lazy {
84
+ val map =
85
+ requireNotNull(style.getMap("em")) {
86
+ "Emphasis style not found. JS should always provide defaults."
87
+ }
88
+ EmphasisStyle.fromReadableMap(map, styleParser)
89
+ }
90
+
91
+ val codeStyle: CodeStyle by lazy {
92
+ val map =
93
+ requireNotNull(style.getMap("code")) {
94
+ "Code style not found. JS should always provide defaults."
95
+ }
96
+ CodeStyle.fromReadableMap(map, styleParser)
97
+ }
98
+
99
+ val imageStyle: ImageStyle by lazy {
100
+ val map =
101
+ requireNotNull(style.getMap("image")) {
102
+ "Image style not found. JS should always provide defaults."
103
+ }
104
+ ImageStyle.fromReadableMap(map, styleParser)
105
+ }
106
+
107
+ val inlineImageStyle: InlineImageStyle by lazy {
108
+ val map =
109
+ requireNotNull(style.getMap("inlineImage")) {
110
+ "InlineImage style not found. JS should always provide defaults."
111
+ }
112
+ InlineImageStyle.fromReadableMap(map, styleParser)
113
+ }
114
+
115
+ val blockquoteStyle: BlockquoteStyle by lazy {
116
+ val map =
117
+ requireNotNull(style.getMap("blockquote")) {
118
+ "Blockquote style not found. JS should always provide defaults."
119
+ }
120
+ BlockquoteStyle.fromReadableMap(map, styleParser)
121
+ }
122
+
123
+ val listStyle: ListStyle by lazy {
124
+ val map =
125
+ requireNotNull(style.getMap("list")) {
126
+ "List style not found. JS should always provide defaults."
127
+ }
128
+ ListStyle.fromReadableMap(map, styleParser)
129
+ }
130
+
131
+ val codeBlockStyle: CodeBlockStyle by lazy {
132
+ val map =
133
+ requireNotNull(style.getMap("codeBlock")) {
134
+ "CodeBlock style not found. JS should always provide defaults."
135
+ }
136
+ CodeBlockStyle.fromReadableMap(map, styleParser)
137
+ }
138
+
139
+ val thematicBreakStyle: ThematicBreakStyle by lazy {
140
+ val map =
141
+ requireNotNull(style.getMap("thematicBreak")) {
142
+ "ThematicBreak style not found. JS should always provide defaults."
143
+ }
144
+ ThematicBreakStyle.fromReadableMap(map, styleParser)
145
+ }
146
+
147
+ override fun equals(other: Any?): Boolean {
148
+ if (this === other) return true
149
+ if (other !is StyleConfig) return false
150
+
151
+ return paragraphStyle == other.paragraphStyle &&
152
+ headingStyles.contentEquals(other.headingStyles) &&
153
+ linkStyle == other.linkStyle &&
154
+ strongStyle == other.strongStyle &&
155
+ emphasisStyle == other.emphasisStyle &&
156
+ codeStyle == other.codeStyle &&
157
+ imageStyle == other.imageStyle &&
158
+ inlineImageStyle == other.inlineImageStyle &&
159
+ blockquoteStyle == other.blockquoteStyle &&
160
+ listStyle == other.listStyle &&
161
+ codeBlockStyle == other.codeBlockStyle &&
162
+ thematicBreakStyle == other.thematicBreakStyle
163
+ }
164
+
165
+ override fun hashCode(): Int {
166
+ var result = paragraphStyle.hashCode()
167
+ result = 31 * result + headingStyles.contentHashCode()
168
+ result = 31 * result + linkStyle.hashCode()
169
+ result = 31 * result + strongStyle.hashCode()
170
+ result = 31 * result + emphasisStyle.hashCode()
171
+ result = 31 * result + codeStyle.hashCode()
172
+ result = 31 * result + imageStyle.hashCode()
173
+ result = 31 * result + inlineImageStyle.hashCode()
174
+ result = 31 * result + blockquoteStyle.hashCode()
175
+ result = 31 * result + listStyle.hashCode()
176
+ result = 31 * result + codeBlockStyle.hashCode()
177
+ result = 31 * result + thematicBreakStyle.hashCode()
178
+ return result
179
+ }
180
+ }
@@ -0,0 +1,75 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import android.content.Context
4
+ import com.facebook.react.bridge.ColorPropConverter
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.uimanager.PixelUtil
7
+
8
+ /**
9
+ * Helper class for parsing style values from ReadableMap.
10
+ * Provides common parsing utilities used by all style factory functions.
11
+ */
12
+ class StyleParser(
13
+ private val context: Context,
14
+ ) {
15
+ fun parseOptionalColor(
16
+ map: ReadableMap,
17
+ key: String,
18
+ ): Int? {
19
+ if (!map.hasKey(key) || map.isNull(key)) {
20
+ return null
21
+ }
22
+ val colorValue = map.getDouble(key)
23
+ return ColorPropConverter.getColor(colorValue, context)
24
+ }
25
+
26
+ fun parseColor(
27
+ map: ReadableMap,
28
+ key: String,
29
+ ): Int =
30
+ parseOptionalColor(map, key)
31
+ ?: throw IllegalArgumentException("Color key '$key' is missing, null, or invalid")
32
+
33
+ fun parseOptionalDouble(
34
+ map: ReadableMap,
35
+ key: String,
36
+ default: Double = 0.0,
37
+ ): Double =
38
+ if (map.hasKey(key) && !map.isNull(key)) {
39
+ map.getDouble(key)
40
+ } else {
41
+ default
42
+ }
43
+
44
+ fun parseOptionalInt(
45
+ map: ReadableMap,
46
+ key: String,
47
+ default: Int = 0,
48
+ ): Int =
49
+ if (map.hasKey(key) && !map.isNull(key)) {
50
+ map.getInt(key)
51
+ } else {
52
+ default
53
+ }
54
+
55
+ fun parseString(
56
+ map: ReadableMap,
57
+ key: String,
58
+ default: String = "",
59
+ ): String = map.getString(key) ?: default
60
+
61
+ fun parseBoolean(
62
+ map: ReadableMap,
63
+ key: String,
64
+ default: Boolean = false,
65
+ ): Boolean =
66
+ if (map.hasKey(key) && !map.isNull(key)) {
67
+ map.getBoolean(key)
68
+ } else {
69
+ default
70
+ }
71
+
72
+ fun toPixelFromSP(value: Float): Float = PixelUtil.toPixelFromSP(value)
73
+
74
+ fun toPixelFromDIP(value: Float): Float = PixelUtil.toPixelFromDIP(value)
75
+ }
@@ -0,0 +1,23 @@
1
+ package com.swmansion.enriched.markdown.styles
2
+
3
+ import com.facebook.react.bridge.ReadableMap
4
+
5
+ data class ThematicBreakStyle(
6
+ val color: Int,
7
+ val height: Float,
8
+ val marginTop: Float,
9
+ val marginBottom: Float,
10
+ ) {
11
+ companion object {
12
+ fun fromReadableMap(
13
+ map: ReadableMap,
14
+ parser: StyleParser,
15
+ ): ThematicBreakStyle {
16
+ val color = parser.parseColor(map, "color")
17
+ val height = parser.toPixelFromDIP(map.getDouble("height").toFloat())
18
+ val marginTop = parser.toPixelFromDIP(map.getDouble("marginTop").toFloat())
19
+ val marginBottom = parser.toPixelFromDIP(map.getDouble("marginBottom").toFloat())
20
+ return ThematicBreakStyle(color, height, marginTop, marginBottom)
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,91 @@
1
+ package com.swmansion.enriched.markdown.utils
2
+
3
+ import android.content.res.Resources
4
+ import android.graphics.BitmapFactory
5
+ import android.graphics.Canvas
6
+ import android.graphics.Color
7
+ import android.graphics.ColorFilter
8
+ import android.graphics.drawable.Drawable
9
+ import android.os.Handler
10
+ import android.os.Looper
11
+ import android.util.Log
12
+ import androidx.core.graphics.drawable.toDrawable
13
+ import java.net.URL
14
+ import java.util.concurrent.Executors
15
+
16
+ /**
17
+ * Custom Drawable that loads images asynchronously from URLs.
18
+ */
19
+ class AsyncDrawable(
20
+ private val url: String,
21
+ ) : Drawable() {
22
+ // 1. Use a shared companion executor to avoid thread leakage per instance
23
+ companion object {
24
+ private val sharedExecutor = Executors.newFixedThreadPool(4)
25
+ private val mainHandler = Handler(Looper.getMainLooper())
26
+ }
27
+
28
+ var internalDrawable: Drawable = Color.TRANSPARENT.toDrawable()
29
+
30
+ // 2. Track loading state more granularly
31
+ var isLoaded = false
32
+ private set
33
+
34
+ var onLoaded: (() -> Unit)? = null
35
+
36
+ init {
37
+ load()
38
+ }
39
+
40
+ private fun load() {
41
+ sharedExecutor.execute {
42
+ try {
43
+ // 3. Proper Resource Management: Use 'use' to close the stream automatically
44
+ val bitmap =
45
+ URL(url).openStream().use {
46
+ BitmapFactory.decodeStream(it)
47
+ }
48
+
49
+ mainHandler.post {
50
+ bitmap?.let {
51
+ val drawable = it.toDrawable(Resources.getSystem())
52
+ drawable.bounds = bounds
53
+ internalDrawable = drawable
54
+ }
55
+ isLoaded = true
56
+ onLoaded?.invoke()
57
+ invalidateSelf() // 4. Critical: Tell the system to redraw
58
+ }
59
+ } catch (e: Exception) {
60
+ Log.e("AsyncDrawable", "Failed to load image from: $url", e)
61
+ mainHandler.post {
62
+ isLoaded = true
63
+ onLoaded?.invoke()
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ override fun draw(canvas: Canvas) = internalDrawable.draw(canvas)
70
+
71
+ override fun setAlpha(alpha: Int) {
72
+ internalDrawable.alpha = alpha
73
+ }
74
+
75
+ override fun setColorFilter(colorFilter: ColorFilter?) {
76
+ internalDrawable.colorFilter = colorFilter
77
+ }
78
+
79
+ @Deprecated("Deprecated in Java")
80
+ override fun getOpacity(): Int = internalDrawable.opacity
81
+
82
+ override fun setBounds(
83
+ left: Int,
84
+ top: Int,
85
+ right: Int,
86
+ bottom: Int,
87
+ ) {
88
+ super.setBounds(left, top, right, bottom)
89
+ internalDrawable.setBounds(left, top, right, bottom)
90
+ }
91
+ }