react-native-marcus 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 (294) hide show
  1. package/README.md +220 -63
  2. package/RNMarcus.podspec +6 -0
  3. package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +2 -1
  4. package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorView.kt +168 -0
  5. package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManager.kt +38 -0
  6. package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManagerSpec.kt +19 -0
  7. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +23 -1
  8. package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPainter.kt +147 -0
  9. package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPass.kt +19 -0
  10. package/android/src/main/java/app/getbullet/marcus/MarkdownCopy.kt +87 -0
  11. package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +652 -113
  12. package/android/src/main/java/app/getbullet/marcus/MarkdownRanges.kt +47 -0
  13. package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +140 -61
  14. package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +37 -7
  15. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownAbsoluteLineHeightSpan.kt +48 -0
  16. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +102 -48
  17. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +22 -4
  18. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBulletSpan.kt +78 -0
  19. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpan.kt +177 -0
  20. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontStyleSpan.kt +32 -0
  21. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontWeightSpan.kt +34 -0
  22. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +24 -11
  23. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLetterSpacingSpan.kt +32 -0
  24. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownTextShadowSpan.kt +32 -0
  25. package/android/src/main/new_arch/CMakeLists.txt +17 -0
  26. package/android/src/main/new_arch/RNMarcusSpec.h +1 -0
  27. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.cpp +235 -0
  28. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.h +62 -0
  29. package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
  30. package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
  31. package/android/src/test/java/app/getbullet/marcus/MarkdownCopyTest.kt +69 -0
  32. package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +170 -25
  33. package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +22 -5
  34. package/android/src/test/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpanTest.kt +91 -0
  35. package/android/src/test/resources/render-model.txt +221 -16
  36. package/apple/MarcusSwizzle.h +25 -0
  37. package/apple/MarcusTextDecoratorComponentView.h +22 -0
  38. package/apple/MarcusTextDecoratorComponentView.mm +72 -0
  39. package/apple/MarcusTextDecoratorShadowNode.h +62 -0
  40. package/apple/MarcusTextDecoratorShadowNode.mm +192 -0
  41. package/apple/MarcusTextDecoratorViewManager.h +4 -0
  42. package/apple/MarcusTextDecoratorViewManager.mm +11 -0
  43. package/apple/MarcusTextInputDecoratorComponentView.mm +1 -1
  44. package/apple/MarcusTextInputDecoratorShadowNode.mm +1 -1
  45. package/apple/MarcusTextLayoutManager.h +40 -0
  46. package/apple/MarcusTextLayoutManager.mm +173 -0
  47. package/apple/MarkdownAttributes.h +23 -2
  48. package/apple/MarkdownAttributes.m +6 -0
  49. package/apple/MarkdownCopy.swift +63 -0
  50. package/apple/MarkdownDecorator.swift +2 -2
  51. package/apple/MarkdownFormatter+React.swift +23 -0
  52. package/apple/MarkdownFormatter.swift +869 -148
  53. package/apple/MarkdownParagraphLayoutManager.swift +455 -0
  54. package/apple/MarkdownSwiftInterop.h +0 -1
  55. package/apple/MarkdownTextBackground.swift +59 -1
  56. package/apple/MarkdownTextFieldObserver.swift +2 -2
  57. package/apple/MarkdownTextLayoutFragment.swift +159 -33
  58. package/apple/MarkdownTextLayoutManagerDelegate.swift +67 -3
  59. package/apple/MarkdownTextStorageDelegate.swift +2 -2
  60. package/apple/MarkdownTextViewObserver.swift +2 -2
  61. package/apple/MarkdownUtils.swift +38 -0
  62. package/apple/MarkdownWritingDirection.swift +132 -0
  63. package/apple/RCTMarcusStyle+Codegen.h +115 -9
  64. package/apple/RCTMarcusStyle.h +128 -31
  65. package/apple/RCTMarcusStyle.m +48 -0
  66. package/apple/RCTParagraphComponentView+Marcus.h +17 -0
  67. package/apple/RCTParagraphComponentView+Marcus.mm +38 -0
  68. package/apple/RCTTextInputComponentView+Marcus.mm +1 -25
  69. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorState.h +37 -0
  70. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorViewComponentDescriptor.h +17 -0
  71. package/lib/commonjs/MarcusTextDecoratorViewNativeComponent.ts +199 -0
  72. package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
  73. package/lib/commonjs/MarkdownText.js +330 -0
  74. package/lib/commonjs/MarkdownText.js.map +1 -0
  75. package/lib/commonjs/MarkdownText.web.js +529 -0
  76. package/lib/commonjs/MarkdownText.web.js.map +1 -0
  77. package/lib/commonjs/MarkdownTextInput.js +22 -27
  78. package/lib/commonjs/MarkdownTextInput.js.map +1 -1
  79. package/lib/commonjs/MarkdownTextInput.web.js +12 -7
  80. package/lib/commonjs/MarkdownTextInput.web.js.map +1 -1
  81. package/lib/commonjs/atomUtils.js +112 -0
  82. package/lib/commonjs/atomUtils.js.map +1 -0
  83. package/lib/commonjs/childrenUtils.js +36 -0
  84. package/lib/commonjs/childrenUtils.js.map +1 -0
  85. package/lib/commonjs/index.js +8 -7
  86. package/lib/commonjs/index.js.map +1 -1
  87. package/lib/commonjs/math/environment.js +69 -0
  88. package/lib/commonjs/math/environment.js.map +1 -0
  89. package/lib/commonjs/math/index.js +61 -0
  90. package/lib/commonjs/math/index.js.map +1 -0
  91. package/lib/commonjs/math/mathjax.js +548 -0
  92. package/lib/commonjs/math/mathjax.js.map +1 -0
  93. package/lib/commonjs/metro.js +172 -0
  94. package/lib/commonjs/metro.js.map +1 -0
  95. package/lib/commonjs/parser/index.d.ts +3 -0
  96. package/lib/commonjs/parser/index.js +450 -42
  97. package/lib/commonjs/parser/index.js.map +4 -4
  98. package/lib/commonjs/stripUtils.js +743 -0
  99. package/lib/commonjs/stripUtils.js.map +1 -0
  100. package/lib/commonjs/styleUtils.js +194 -23
  101. package/lib/commonjs/styleUtils.js.map +1 -1
  102. package/lib/commonjs/web/MarkdownElements.css +67 -0
  103. package/lib/commonjs/web/MarkdownTextInput.css +9 -7
  104. package/lib/commonjs/web/utils/blockLayout.js +95 -7
  105. package/lib/commonjs/web/utils/blockLayout.js.map +1 -1
  106. package/lib/commonjs/web/utils/blockUtils.js +327 -54
  107. package/lib/commonjs/web/utils/blockUtils.js.map +1 -1
  108. package/lib/commonjs/web/utils/elementUtils.js +80 -0
  109. package/lib/commonjs/web/utils/elementUtils.js.map +1 -0
  110. package/lib/commonjs/web/utils/parserUtils.js +84 -28
  111. package/lib/commonjs/web/utils/parserUtils.js.map +1 -1
  112. package/lib/commonjs/web/utils/treeUtils.js +6 -0
  113. package/lib/commonjs/web/utils/treeUtils.js.map +1 -1
  114. package/lib/commonjs/web/utils/webStyleUtils.js +25 -5
  115. package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -1
  116. package/lib/module/MarcusTextDecoratorViewNativeComponent.ts +199 -0
  117. package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
  118. package/lib/module/MarkdownText.js +325 -0
  119. package/lib/module/MarkdownText.js.map +1 -0
  120. package/lib/module/MarkdownText.web.js +524 -0
  121. package/lib/module/MarkdownText.web.js.map +1 -0
  122. package/lib/module/MarkdownTextInput.js +24 -29
  123. package/lib/module/MarkdownTextInput.js.map +1 -1
  124. package/lib/module/MarkdownTextInput.web.js +12 -7
  125. package/lib/module/MarkdownTextInput.web.js.map +1 -1
  126. package/lib/module/atomUtils.js +106 -0
  127. package/lib/module/atomUtils.js.map +1 -0
  128. package/lib/module/childrenUtils.js +33 -0
  129. package/lib/module/childrenUtils.js.map +1 -0
  130. package/lib/module/index.js +1 -1
  131. package/lib/module/index.js.map +1 -1
  132. package/lib/module/math/environment.js +67 -0
  133. package/lib/module/math/environment.js.map +1 -0
  134. package/lib/module/math/index.js +56 -0
  135. package/lib/module/math/index.js.map +1 -0
  136. package/lib/module/math/mathjax.js +541 -0
  137. package/lib/module/math/mathjax.js.map +1 -0
  138. package/lib/module/metro.js +169 -0
  139. package/lib/module/metro.js.map +1 -0
  140. package/lib/module/parser/index.d.ts +3 -0
  141. package/lib/module/parser/index.js +450 -42
  142. package/lib/module/parser/index.js.map +4 -4
  143. package/lib/module/stripUtils.js +739 -0
  144. package/lib/module/stripUtils.js.map +1 -0
  145. package/lib/module/styleUtils.js +196 -25
  146. package/lib/module/styleUtils.js.map +1 -1
  147. package/lib/module/web/MarkdownElements.css +67 -0
  148. package/lib/module/web/MarkdownTextInput.css +9 -7
  149. package/lib/module/web/utils/blockLayout.js +94 -8
  150. package/lib/module/web/utils/blockLayout.js.map +1 -1
  151. package/lib/module/web/utils/blockUtils.js +328 -56
  152. package/lib/module/web/utils/blockUtils.js.map +1 -1
  153. package/lib/module/web/utils/elementUtils.js +75 -0
  154. package/lib/module/web/utils/elementUtils.js.map +1 -0
  155. package/lib/module/web/utils/parserUtils.js +86 -30
  156. package/lib/module/web/utils/parserUtils.js.map +1 -1
  157. package/lib/module/web/utils/treeUtils.js +6 -0
  158. package/lib/module/web/utils/treeUtils.js.map +1 -1
  159. package/lib/module/web/utils/webStyleUtils.js +25 -5
  160. package/lib/module/web/utils/webStyleUtils.js.map +1 -1
  161. package/lib/typescript/commonjs/e2e/links.test.d.ts +2 -0
  162. package/lib/typescript/commonjs/e2e/links.test.d.ts.map +1 -0
  163. package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
  164. package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
  165. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
  166. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
  167. package/lib/typescript/commonjs/src/MarkdownText.d.ts +127 -0
  168. package/lib/typescript/commonjs/src/MarkdownText.d.ts.map +1 -0
  169. package/lib/typescript/commonjs/src/MarkdownText.web.d.ts +126 -0
  170. package/lib/typescript/commonjs/src/MarkdownText.web.d.ts.map +1 -0
  171. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +23 -1
  172. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +26 -4
  174. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -1
  175. package/lib/typescript/commonjs/src/atomUtils.d.ts +58 -0
  176. package/lib/typescript/commonjs/src/atomUtils.d.ts.map +1 -0
  177. package/lib/typescript/commonjs/src/childrenUtils.d.ts +12 -0
  178. package/lib/typescript/commonjs/src/childrenUtils.d.ts.map +1 -0
  179. package/lib/typescript/commonjs/src/commonTypes.d.ts +39 -3
  180. package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -1
  181. package/lib/typescript/commonjs/src/index.d.ts +2 -1
  182. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  183. package/lib/typescript/commonjs/src/math/environment.d.ts +7 -0
  184. package/lib/typescript/commonjs/src/math/environment.d.ts.map +1 -0
  185. package/lib/typescript/commonjs/src/math/index.d.ts +64 -0
  186. package/lib/typescript/commonjs/src/math/index.d.ts.map +1 -0
  187. package/lib/typescript/commonjs/src/math/mathjax.d.ts +63 -0
  188. package/lib/typescript/commonjs/src/math/mathjax.d.ts.map +1 -0
  189. package/lib/typescript/commonjs/src/metro.d.ts +59 -0
  190. package/lib/typescript/commonjs/src/metro.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/src/parser/index.d.ts +3 -3
  192. package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -1
  193. package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/src/rangeUtils.d.ts +1 -1
  195. package/lib/typescript/commonjs/src/stripUtils.d.ts +108 -0
  196. package/lib/typescript/commonjs/src/stripUtils.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/src/styleUtils.d.ts +62 -4
  198. package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -1
  199. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +32 -4
  200. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +20 -8
  202. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts +37 -0
  204. package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +5 -5
  206. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -1
  207. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +6 -1
  208. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -1
  209. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +2 -2
  210. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -1
  211. package/lib/typescript/module/e2e/links.test.d.ts +2 -0
  212. package/lib/typescript/module/e2e/links.test.d.ts.map +1 -0
  213. package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
  214. package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
  215. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
  216. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
  217. package/lib/typescript/module/src/MarkdownText.d.ts +127 -0
  218. package/lib/typescript/module/src/MarkdownText.d.ts.map +1 -0
  219. package/lib/typescript/module/src/MarkdownText.web.d.ts +126 -0
  220. package/lib/typescript/module/src/MarkdownText.web.d.ts.map +1 -0
  221. package/lib/typescript/module/src/MarkdownTextInput.d.ts +23 -1
  222. package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -1
  223. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +26 -4
  224. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -1
  225. package/lib/typescript/module/src/atomUtils.d.ts +58 -0
  226. package/lib/typescript/module/src/atomUtils.d.ts.map +1 -0
  227. package/lib/typescript/module/src/childrenUtils.d.ts +12 -0
  228. package/lib/typescript/module/src/childrenUtils.d.ts.map +1 -0
  229. package/lib/typescript/module/src/commonTypes.d.ts +39 -3
  230. package/lib/typescript/module/src/commonTypes.d.ts.map +1 -1
  231. package/lib/typescript/module/src/index.d.ts +2 -1
  232. package/lib/typescript/module/src/index.d.ts.map +1 -1
  233. package/lib/typescript/module/src/math/environment.d.ts +7 -0
  234. package/lib/typescript/module/src/math/environment.d.ts.map +1 -0
  235. package/lib/typescript/module/src/math/index.d.ts +64 -0
  236. package/lib/typescript/module/src/math/index.d.ts.map +1 -0
  237. package/lib/typescript/module/src/math/mathjax.d.ts +63 -0
  238. package/lib/typescript/module/src/math/mathjax.d.ts.map +1 -0
  239. package/lib/typescript/module/src/metro.d.ts +59 -0
  240. package/lib/typescript/module/src/metro.d.ts.map +1 -0
  241. package/lib/typescript/module/src/parser/index.d.ts +3 -3
  242. package/lib/typescript/module/src/parser/index.d.ts.map +1 -1
  243. package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -1
  244. package/lib/typescript/module/src/rangeUtils.d.ts +1 -1
  245. package/lib/typescript/module/src/stripUtils.d.ts +108 -0
  246. package/lib/typescript/module/src/stripUtils.d.ts.map +1 -0
  247. package/lib/typescript/module/src/styleUtils.d.ts +62 -4
  248. package/lib/typescript/module/src/styleUtils.d.ts.map +1 -1
  249. package/lib/typescript/module/src/web/utils/blockLayout.d.ts +32 -4
  250. package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -1
  251. package/lib/typescript/module/src/web/utils/blockUtils.d.ts +20 -8
  252. package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -1
  253. package/lib/typescript/module/src/web/utils/elementUtils.d.ts +37 -0
  254. package/lib/typescript/module/src/web/utils/elementUtils.d.ts.map +1 -0
  255. package/lib/typescript/module/src/web/utils/parserUtils.d.ts +5 -5
  256. package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -1
  257. package/lib/typescript/module/src/web/utils/treeUtils.d.ts +6 -1
  258. package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -1
  259. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +2 -2
  260. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -1
  261. package/package.json +29 -2
  262. package/react-native.config.js +8 -1
  263. package/src/MarcusTextDecoratorViewNativeComponent.ts +199 -0
  264. package/src/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
  265. package/src/MarkdownText.tsx +472 -0
  266. package/src/MarkdownText.web.tsx +668 -0
  267. package/src/MarkdownTextInput.tsx +42 -38
  268. package/src/MarkdownTextInput.web.tsx +36 -13
  269. package/src/atomUtils.ts +112 -0
  270. package/src/childrenUtils.ts +39 -0
  271. package/src/commonTypes.ts +69 -9
  272. package/src/index.tsx +2 -1
  273. package/src/math/environment.ts +68 -0
  274. package/src/math/index.ts +78 -0
  275. package/src/math/mathjax.ts +604 -0
  276. package/src/metro.ts +238 -0
  277. package/src/parser/index.ts +175 -10
  278. package/src/parser/micromark-extension-mentions.ts +104 -11
  279. package/src/stripUtils.ts +919 -0
  280. package/src/styleUtils.ts +290 -26
  281. package/src/web/MarkdownElements.css +67 -0
  282. package/src/web/MarkdownTextInput.css +9 -7
  283. package/src/web/utils/blockLayout.ts +124 -14
  284. package/src/web/utils/blockUtils.ts +365 -59
  285. package/src/web/utils/elementUtils.ts +87 -0
  286. package/src/web/utils/parserUtils.ts +119 -31
  287. package/src/web/utils/treeUtils.ts +6 -1
  288. package/src/web/utils/webStyleUtils.ts +32 -8
  289. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +0 -6
  290. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +0 -6
  291. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +0 -6
  292. package/apple/RCTMarcusStyle+Codegen.mm +0 -64
  293. package/apple/RCTMarcusUtils.h +0 -26
  294. package/apple/RCTMarcusUtils.mm +0 -26
@@ -0,0 +1,192 @@
1
+ #import <RNMarcus/MarcusTextDecoratorShadowNode.h>
2
+
3
+ #import <RNMarcus/MarcusTextLayoutManager.h>
4
+ #import <RNMarcus/RCTMarcusStyle+Codegen.h>
5
+
6
+ #import <react/renderer/components/text/ParagraphShadowNode.h>
7
+ #import <react/renderer/core/ComponentDescriptor.h>
8
+
9
+ namespace facebook {
10
+ namespace react {
11
+
12
+ extern const char MarcusTextDecoratorViewComponentName[] =
13
+ "MarcusTextDecoratorView";
14
+
15
+ MarcusTextDecoratorShadowNode::MarcusTextDecoratorShadowNode(
16
+ ShadowNodeFragment const &fragment,
17
+ ShadowNodeFamily::Shared const &family,
18
+ ShadowNodeTraits traits
19
+ )
20
+ : ConcreteViewShadowNode(fragment, family, traits) {
21
+ initialize();
22
+ createTextLayoutManager();
23
+ makeChildNodeMutable();
24
+
25
+ if (fragment.children) {
26
+ overwriteTextLayoutManager();
27
+ }
28
+ }
29
+
30
+ MarcusTextDecoratorShadowNode::MarcusTextDecoratorShadowNode(
31
+ ShadowNode const &sourceShadowNode,
32
+ ShadowNodeFragment const &fragment
33
+ )
34
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
35
+ initialize();
36
+
37
+ const auto &sourceDecorator =
38
+ static_cast<const MarcusTextDecoratorShadowNode &>(sourceShadowNode);
39
+ textLayoutManager_ = sourceDecorator.textLayoutManager_;
40
+
41
+ // Fabric hands a clone the very same props object whenever nothing about the
42
+ // props changed, so pointer identity is both exact and cheap here. Codegen
43
+ // only emits `operator==` for prop structs under RN_SERIALIZABLE_STATE, which
44
+ // iOS does not define, and hand-written equality over the style would rot the
45
+ // moment a field is added.
46
+ if (textLayoutManager_ == nullptr ||
47
+ getProps().get() != sourceDecorator.getProps().get()) {
48
+ createTextLayoutManager();
49
+ }
50
+
51
+ makeChildNodeMutable();
52
+
53
+ if (fragment.children) {
54
+ overwriteTextLayoutManager();
55
+ }
56
+ }
57
+
58
+ void
59
+ MarcusTextDecoratorShadowNode::initialize() {
60
+ // Setting display: contents style results in ForceFlattenView trait being set
61
+ // on the shadow node. This trait causes the node not to have a host view. By
62
+ // removing the trait, it's possible to force RN to create a host view, layout
63
+ // of which can then be customized.
64
+ ShadowNode::traits_.unset(ShadowNodeTraits::ForceFlattenView);
65
+ }
66
+
67
+ void
68
+ MarcusTextDecoratorShadowNode::makeChildNodeMutable() {
69
+ // When the decorator is cloned and has a child node, the child node should be
70
+ // cloned as well to ensure it is mutable. Cloning it also runs the paragraph's
71
+ // own component descriptor, which resets the layout manager to the shared one
72
+ // -- hence overwriteTextLayoutManager() always following this, never the other
73
+ // way around.
74
+ const auto &children = getChildren();
75
+ if (!children.empty()) {
76
+ react_native_assert(
77
+ children.size() == 1 &&
78
+ "MarcusTextDecoratorView received more than one child"
79
+ );
80
+
81
+ const auto clonedChild = children[0]->clone({});
82
+ replaceChild(*children[0], clonedChild);
83
+ }
84
+ }
85
+
86
+ void
87
+ MarcusTextDecoratorShadowNode::createTextLayoutManager() {
88
+ const auto &props = getConcreteProps();
89
+
90
+ NSMutableArray<MarcusRange *> *ranges =
91
+ [NSMutableArray arrayWithCapacity:props.ranges.size()];
92
+
93
+ for (const auto &range : props.ranges) {
94
+ [ranges addObject:[[MarcusRange alloc]
95
+ initWithType:RCTNSStringFromString(range.type)
96
+ range:NSMakeRange(range.start, range.length)
97
+ depth:static_cast<NSUInteger>(range.depth)]];
98
+ }
99
+
100
+ textLayoutManager_ = std::make_shared<const MarcusTextLayoutManager>(
101
+ getContextContainer(),
102
+ ranges,
103
+ RCTMarcusStyleFromStruct(props.markdownStyle)
104
+ );
105
+ }
106
+
107
+ void
108
+ MarcusTextDecoratorShadowNode::overwriteTextLayoutManager() {
109
+ const auto &children = getChildren();
110
+ if (children.empty()) {
111
+ return;
112
+ }
113
+ react_native_assert(
114
+ children.size() == 1 &&
115
+ "MarcusTextDecoratorView received more than one child"
116
+ );
117
+
118
+ const auto child =
119
+ std::dynamic_pointer_cast<const ParagraphShadowNode>(children[0]);
120
+
121
+ react_native_assert(
122
+ child != nullptr &&
123
+ "MarcusTextDecoratorView received child other than a Text"
124
+ );
125
+
126
+ if (child == nullptr) {
127
+ return;
128
+ }
129
+
130
+ child->ensureUnsealed();
131
+
132
+ const auto mutableChild =
133
+ std::const_pointer_cast<ParagraphShadowNode>(child);
134
+ mutableChild->setTextLayoutManager(textLayoutManager_);
135
+ }
136
+
137
+ void
138
+ MarcusTextDecoratorShadowNode::appendChild(
139
+ const std::shared_ptr<const ShadowNode> &child
140
+ ) {
141
+ YogaLayoutableShadowNode::appendChild(child);
142
+
143
+ overwriteTextLayoutManager();
144
+ }
145
+
146
+ void
147
+ MarcusTextDecoratorShadowNode::replaceChild(
148
+ const ShadowNode &oldChild,
149
+ const std::shared_ptr<const ShadowNode> &newChild,
150
+ size_t suggestedIndex
151
+ ) {
152
+ YogaLayoutableShadowNode::replaceChild(oldChild, newChild, suggestedIndex);
153
+
154
+ overwriteTextLayoutManager();
155
+ }
156
+
157
+ void
158
+ MarcusTextDecoratorShadowNode::layout(LayoutContext layoutContext) {
159
+ YogaLayoutableShadowNode::layout(layoutContext);
160
+
161
+ const auto &children = getChildren();
162
+ react_native_assert(
163
+ children.size() == 1 &&
164
+ "MarcusTextDecoratorView didn't receive exactly one child"
165
+ );
166
+
167
+ if (children.size() != 1) {
168
+ return;
169
+ }
170
+
171
+ auto child =
172
+ std::static_pointer_cast<const YogaLayoutableShadowNode>(children[0]);
173
+ child->ensureUnsealed();
174
+ auto mutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(child);
175
+
176
+ // Since nodes with display: contents are skipped during layout, they have
177
+ // zero-layout. To properly display the view, assign the layout metrics from
178
+ // the child (the paragraph, which was calculated by Yoga) to the decorator
179
+ // view.
180
+ auto childMetrics = child->getLayoutMetrics();
181
+ setLayoutMetrics(childMetrics); // makes a copy
182
+
183
+ // Then, it's also needed to update the metrics on the child as the position
184
+ // is relative to the parent, which was just moved above. By zeroing the
185
+ // origin, the child is effectively moved to the same position it was before
186
+ // the manipulation here.
187
+ childMetrics.frame.origin = Point{};
188
+ mutableChild->setLayoutMetrics(childMetrics);
189
+ }
190
+
191
+ } // namespace react
192
+ } // namespace facebook
@@ -0,0 +1,4 @@
1
+ #import <React/RCTViewManager.h>
2
+
3
+ @interface MarcusTextDecoratorViewManager : RCTViewManager
4
+ @end
@@ -0,0 +1,11 @@
1
+ #import <RNMarcus/MarcusTextDecoratorViewManager.h>
2
+
3
+ @implementation MarcusTextDecoratorViewManager
4
+
5
+ RCT_EXPORT_MODULE(MarcusTextDecoratorView)
6
+
7
+ RCT_EXPORT_VIEW_PROPERTY(markdownStyle, NSDictionary)
8
+
9
+ RCT_EXPORT_VIEW_PROPERTY(ranges, NSArray)
10
+
11
+ @end
@@ -95,7 +95,7 @@ using namespace facebook::react;
95
95
  // whenever the props object is recreated -- but hand-written equality over
96
96
  // ~27 fields would rot silently the moment a style prop is added.
97
97
  _decorator.markdownStyle =
98
- [[RCTMarcusStyle alloc] initWithStruct:newViewProps.markdownStyle];
98
+ RCTMarcusStyleFromStruct(newViewProps.markdownStyle);
99
99
 
100
100
  [_decorator applyNewStyles];
101
101
 
@@ -128,7 +128,7 @@ MarcusTextInputDecoratorShadowNode::
128
128
  }
129
129
 
130
130
  RCTMarcusStyle *markdownStyle =
131
- [[RCTMarcusStyle alloc] initWithStruct:decoratorProps.markdownStyle];
131
+ RCTMarcusStyleFromStruct(decoratorProps.markdownStyle);
132
132
  NSNumber *parserId = [NSNumber numberWithInt:decoratorProps.parserId];
133
133
 
134
134
  // convert the attibuted string stored in state to
@@ -0,0 +1,40 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ #import <RNMarcus/MarcusRange.h>
6
+ #import <RNMarcus/RCTMarcusStyle.h>
7
+
8
+ #include <react/renderer/textlayoutmanager/TextLayoutManager.h>
9
+
10
+ #include <memory>
11
+
12
+ namespace facebook {
13
+ namespace react {
14
+
15
+ /*
16
+ * A `TextLayoutManager` that formats before it lays out.
17
+ *
18
+ * Everything `RCTParagraphComponentView` does with text -- measuring it,
19
+ * drawing it, hit-testing it, enumerating its lines -- goes through the
20
+ * `RCTTextLayoutManager` this owns, and each of those paths converts the
21
+ * shadow tree's `AttributedString` into an `NSAttributedString` first. That
22
+ * conversion is the only place markdown has to be applied, which is why the
23
+ * `Text` decorator needs none of the measure-callback surgery the `TextInput`
24
+ * one does: handing the child paragraph one of these covers every path at once.
25
+ *
26
+ * Immutable once constructed. The decorator builds a new one when its props
27
+ * change rather than mutating this, so the commit thread is never writing style
28
+ * or ranges while the main thread draws with them.
29
+ */
30
+ class MarcusTextLayoutManager : public TextLayoutManager {
31
+ public:
32
+ MarcusTextLayoutManager(
33
+ const std::shared_ptr<const ContextContainer> &contextContainer,
34
+ NSArray<MarcusRange *> *ranges,
35
+ RCTMarcusStyle *markdownStyle
36
+ );
37
+ };
38
+
39
+ } // namespace react
40
+ } // namespace facebook
@@ -0,0 +1,173 @@
1
+ #import <RNMarcus/MarcusTextLayoutManager.h>
2
+ #import <RNMarcus/MarkdownSwiftInterop.h>
3
+
4
+ #import <react/debug/react_native_assert.h>
5
+ #import <react/renderer/textlayoutmanager/RCTTextLayoutManager.h>
6
+ #import <react/utils/ManagedObjectWrapper.h>
7
+
8
+ using namespace facebook::react;
9
+
10
+ // The one seam every text path funnels through. It is private to
11
+ // RCTTextLayoutManager, so it is redeclared here to be overridden; the
12
+ // alternative is reimplementing five public methods that each need
13
+ // `_textStorageAndLayoutManagerWithAttributesString:`, which is private too.
14
+ //
15
+ // If React Native renames it the override silently stops being called, so the
16
+ // subclass asserts on the selector at construction rather than letting
17
+ // formatting quietly disappear.
18
+ @interface RCTTextLayoutManager (Marcus)
19
+ - (NSAttributedString *)
20
+ _nsAttributedStringFromAttributedString:(facebook::react::AttributedString)attributedString;
21
+ - (NSTextStorage *)
22
+ _textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString
23
+ paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
24
+ size:(CGSize)size;
25
+ @end
26
+
27
+ @interface MarcusRCTTextLayoutManager : RCTTextLayoutManager
28
+
29
+ @property(nonatomic, copy) NSArray<MarcusRange *> *ranges;
30
+ @property(nonatomic, strong) RCTMarcusStyle *markdownStyle;
31
+
32
+ @end
33
+
34
+ @implementation MarcusRCTTextLayoutManager
35
+
36
+ - (NSAttributedString *)
37
+ _nsAttributedStringFromAttributedString:(AttributedString)attributedString {
38
+ NSAttributedString *unformatted =
39
+ [super _nsAttributedStringFromAttributedString:attributedString];
40
+
41
+ if (_markdownStyle == nil || unformatted.length == 0) {
42
+ return unformatted;
43
+ }
44
+
45
+ // Superclass caches what it returns, so the copy is not optional.
46
+ NSMutableAttributedString *formatted =
47
+ [[NSMutableAttributedString alloc] initWithAttributedString:unformatted];
48
+
49
+ // Unlike the text input there is no separate notion of default attributes: a
50
+ // paragraph's own attributes are already on the string, fragment by fragment,
51
+ // and the formatter is asked to leave them alone. What it still needs is a
52
+ // paragraph style to build indents from, which is what these supply.
53
+ NSDictionary<NSAttributedStringKey, id> *defaultTextAttributes =
54
+ [unformatted attributesAtIndex:0 effectiveRange:NULL];
55
+
56
+ [MarkdownFormatter formatParagraph:formatted
57
+ defaultTextAttributes:defaultTextAttributes
58
+ ranges:_ranges
59
+ style:_markdownStyle];
60
+
61
+ return formatted;
62
+ }
63
+
64
+ // The second seam, for the two shapes that are not attributes at all. Every
65
+ // path builds its layout here, and swapping in a subclass is the only way to
66
+ // reach the background drawing pass -- `drawAttributedString:` takes the layout
67
+ // manager this returns and never asks what class it is.
68
+ //
69
+ // Super is called rather than reimplemented so that whatever else React Native
70
+ // does to a text container -- line breaking, font scaling, baseline offset --
71
+ // keeps happening, and keeps happening the same way for measurement as for
72
+ // drawing.
73
+ - (NSTextStorage *)
74
+ _textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString
75
+ paragraphAttributes:(ParagraphAttributes)paragraphAttributes
76
+ size:(CGSize)size {
77
+ NSTextStorage *textStorage =
78
+ [super _textStorageAndLayoutManagerWithAttributesString:attributedString
79
+ paragraphAttributes:paragraphAttributes
80
+ size:size];
81
+
82
+ if (_markdownStyle == nil || textStorage.layoutManagers.count != 1) {
83
+ return textStorage;
84
+ }
85
+
86
+ NSLayoutManager *original = textStorage.layoutManagers.firstObject;
87
+
88
+ if (original.textContainers.count != 1 ||
89
+ [original isKindOfClass:[MarkdownParagraphLayoutManager class]]) {
90
+ return textStorage;
91
+ }
92
+
93
+ NSTextContainer *textContainer = original.textContainers.firstObject;
94
+ MarkdownParagraphLayoutManager *replacement =
95
+ [MarkdownParagraphLayoutManager new];
96
+ replacement.usesFontLeading = original.usesFontLeading;
97
+ replacement.markdownStyle = _markdownStyle;
98
+
99
+ [original removeTextContainerAtIndex:0];
100
+ [replacement addTextContainer:textContainer];
101
+ [textStorage addLayoutManager:replacement];
102
+ [textStorage removeLayoutManager:original];
103
+
104
+ return textStorage;
105
+ }
106
+
107
+ /**
108
+ * Where a press lands.
109
+ *
110
+ * The touch arrives in the paragraph view's own coordinates -- padding
111
+ * included -- while the layout it is measured against starts at the content
112
+ * frame, so on a `Text` with any padding at all React Native looks up the
113
+ * character that many points down and to the right of the one under the
114
+ * finger. With 8pt of padding and a 19pt line that is the bottom half of every
115
+ * line pressing the line below it, which is most of what makes a link feel
116
+ * like it has to be aimed at.
117
+ *
118
+ * Nothing else needs the untranslated point: this is the only method that
119
+ * takes one.
120
+ */
121
+ - (std::shared_ptr<const EventEmitter>)
122
+ getEventEmitterWithAttributeString:(AttributedString)attributedString
123
+ paragraphAttributes:(ParagraphAttributes)paragraphAttributes
124
+ frame:(CGRect)frame
125
+ atPoint:(CGPoint)point {
126
+ CGPoint inContent =
127
+ CGPointMake(point.x - frame.origin.x, point.y - frame.origin.y);
128
+
129
+ return [super getEventEmitterWithAttributeString:attributedString
130
+ paragraphAttributes:paragraphAttributes
131
+ frame:frame
132
+ atPoint:inContent];
133
+ }
134
+
135
+ @end
136
+
137
+ namespace facebook {
138
+ namespace react {
139
+
140
+ MarcusTextLayoutManager::MarcusTextLayoutManager(
141
+ const std::shared_ptr<const ContextContainer> &contextContainer,
142
+ NSArray<MarcusRange *> *ranges,
143
+ RCTMarcusStyle *markdownStyle
144
+ )
145
+ : TextLayoutManager(contextContainer) {
146
+ react_native_assert(
147
+ [RCTTextLayoutManager instancesRespondToSelector:
148
+ @selector(_nsAttributedStringFromAttributedString:)] &&
149
+ "RCTTextLayoutManager no longer converts attributed strings through "
150
+ "-_nsAttributedStringFromAttributedString:, so markdown formatting would "
151
+ "never be applied"
152
+ );
153
+ react_native_assert(
154
+ [RCTTextLayoutManager
155
+ instancesRespondToSelector:
156
+ @selector(_textStorageAndLayoutManagerWithAttributesString:paragraphAttributes:size:)] &&
157
+ "RCTTextLayoutManager no longer builds its layout through "
158
+ "-_textStorageAndLayoutManagerWithAttributesString:paragraphAttributes:size:, "
159
+ "so blockquote ribbons and mention pills would never be drawn"
160
+ );
161
+
162
+ MarcusRCTTextLayoutManager *manager = [MarcusRCTTextLayoutManager new];
163
+ manager.ranges = ranges;
164
+ manager.markdownStyle = markdownStyle;
165
+
166
+ // Replaces the plain one the base constructor just made. Every method on
167
+ // TextLayoutManager reads this member rather than a type, so none of them
168
+ // need to be virtual for the subclass to take effect.
169
+ nativeTextLayoutManager_ = wrapManagedObject(manager);
170
+ }
171
+
172
+ } // namespace react
173
+ } // namespace facebook
@@ -16,16 +16,37 @@ FOUNDATION_EXPORT const
16
16
  FOUNDATION_EXPORT const NSAttributedStringKey
17
17
  RCTMarcusTextBackgroundAttributeName NS_SWIFT_NAME(marcusTextBackground);
18
18
 
19
+ // Carries a MarkdownCodeBlock over a fenced or indented block, drawn as one box
20
+ // behind the whole thing rather than as a background behind its glyphs.
21
+ FOUNDATION_EXPORT const NSAttributedStringKey
22
+ RCTMarcusCodeBlockAttributeName NS_SWIFT_NAME(marcusCodeBlock);
23
+
24
+ // Carries a MarkdownListBullet over the marker character of an unordered list
25
+ // item, whose glyph is left undrawn so that the circle can be drawn in its
26
+ // place. Only a display ever carries it: an input shows the marker you typed.
27
+ FOUNDATION_EXPORT const NSAttributedStringKey
28
+ RCTMarcusListBulletAttributeName NS_SWIFT_NAME(marcusListBullet);
29
+
19
30
  // Blockquote nesting level, used to draw the ribbons.
20
31
  FOUNDATION_EXPORT const NSAttributedStringKey
21
32
  RCTMarcusBlockquoteDepthAttributeName NS_SWIFT_NAME(marcusBlockquoteDepth);
22
33
 
23
- // Distance from the paragraph's left edge to the blockquote's own box: the
34
+ // Distance from the line's leading edge to the blockquote's own box: the
24
35
  // indent the line already carried when the blockquote was applied, plus any
25
36
  // room left for a list marker drawn in front of the ribbons. They are drawn
26
37
  // from there rather than from the text origin, which also moves with containers
27
- // nested inside the quote (a list, say).
38
+ // nested inside the quote (a list, say). Leading rather than left, because a
39
+ // head indent is: which edge it is measured from is `marcusRightToLeft`.
28
40
  FOUNDATION_EXPORT const NSAttributedStringKey
29
41
  RCTMarcusBlockquoteIndentAttributeName NS_SWIFT_NAME(marcusBlockquoteIndent);
30
42
 
43
+ // Set over a line that reads right to left, and only over such a line: left to
44
+ // right is the absence of it. The shapes drawn beside the text -- a quote's
45
+ // ribbons, a code block's box -- are placed from the edge the line begins at,
46
+ // and nothing else in the string says which edge that is. UIKit resolves
47
+ // `NSWritingDirectionNatural` while laying out and keeps the answer to itself,
48
+ // so `MarkdownWritingDirection` works out the same one while formatting.
49
+ FOUNDATION_EXPORT const NSAttributedStringKey
50
+ RCTMarcusRightToLeftAttributeName NS_SWIFT_NAME(marcusRightToLeft);
51
+
31
52
  NS_ASSUME_NONNULL_END
@@ -3,7 +3,13 @@
3
3
  const NSAttributedStringKey RCTMarcusTextAttributeName = @"RCTMarcusText";
4
4
  const NSAttributedStringKey RCTMarcusTextBackgroundAttributeName =
5
5
  @"RCTMarcusTextBackground";
6
+ const NSAttributedStringKey RCTMarcusCodeBlockAttributeName =
7
+ @"RCTMarcusCodeBlock";
8
+ const NSAttributedStringKey RCTMarcusListBulletAttributeName =
9
+ @"RCTMarcusListBullet";
6
10
  const NSAttributedStringKey RCTMarcusBlockquoteDepthAttributeName =
7
11
  @"RCTMarcusBlockquoteDepth";
8
12
  const NSAttributedStringKey RCTMarcusBlockquoteIndentAttributeName =
9
13
  @"RCTMarcusBlockquoteIndent";
14
+ const NSAttributedStringKey RCTMarcusRightToLeftAttributeName =
15
+ @"RCTMarcusRightToLeft";
@@ -0,0 +1,63 @@
1
+ import Foundation
2
+
3
+ /// What a copied paragraph puts on the pasteboard.
4
+ ///
5
+ /// A view nested in a `Text` -- a drawn equation, an image -- is one U+FFFC in
6
+ /// the string TextKit lays out, and U+FFFC is what the platform's own copy
7
+ /// writes: a message with an equation in it arrives in the next application
8
+ /// with an empty box where the maths was. So each of those characters is
9
+ /// written back out as the markdown it stands for.
10
+ ///
11
+ /// The offsets come from JavaScript, measured against the stripped text. That
12
+ /// is the same string the ranges are measured against and the same one React
13
+ /// Native laid out -- the strip left behind exactly the one character an
14
+ /// attachment costs -- so there is nothing to remap here.
15
+ ///
16
+ /// The whole paragraph, rather than a selection of it: React Native's `Text`
17
+ /// has no partial selection on iOS, and `copy:` is sent for the lot. Android
18
+ /// takes a range because there it can be given one.
19
+ @objc public final class MarkdownCopy: NSObject {
20
+
21
+ /// The paragraph with every placeholder replaced by its source.
22
+ ///
23
+ /// The two arrays are one list said in the only shape that crosses into
24
+ /// Objective-C: `indices[i]` is where `sources[i]` goes. They arrive in text
25
+ /// order and each covers exactly one character, so one walk is enough.
26
+ ///
27
+ /// - Parameters:
28
+ /// - text: the string the layout was made from.
29
+ /// - indices: where each placeholder is, in UTF-16 offsets.
30
+ /// - sources: the markdown each placeholder was written as. An empty one
31
+ /// removes the placeholder, which is how an image copies as nothing.
32
+ @objc(substituteInto:indices:sources:)
33
+ public static func substitute(_ text: String, indices: [Int], sources: [String]) -> String {
34
+ // Indexed as an `NSString` rather than a `String`: the offsets count UTF-16
35
+ // code units, which is what the text layout counts, while `String` counts
36
+ // characters a reader would recognise as one. The two disagree over every
37
+ // emoji in the paragraph, and the placeholder after one would land inside a
38
+ // surrogate pair.
39
+ let string = text as NSString
40
+ let length = string.length
41
+ var copied = ""
42
+ var cursor = 0
43
+
44
+ for (index, source) in zip(indices, sources) {
45
+ // Skipped rather than trusted: the props and the string that was laid out
46
+ // are two sides of one commit, and a paragraph mounted between them is the
47
+ // one frame where they can disagree.
48
+ guard index >= cursor, index < length else {
49
+ continue
50
+ }
51
+
52
+ copied += string.substring(with: NSRange(location: cursor, length: index - cursor))
53
+ copied += source
54
+ cursor = index + 1
55
+ }
56
+
57
+ if cursor < length {
58
+ copied += string.substring(from: cursor)
59
+ }
60
+
61
+ return copied
62
+ }
63
+ }
@@ -10,7 +10,7 @@ import UIKit
10
10
  /// implemented in Swift.
11
11
  @objc public final class MarkdownDecorator: NSObject {
12
12
 
13
- private var markdownUtils = RCTMarcusUtils()
13
+ private var markdownUtils = MarkdownUtils()
14
14
 
15
15
  private weak var textView: RCTUITextView?
16
16
  private weak var textField: RCTUITextField?
@@ -44,7 +44,7 @@ import UIKit
44
44
 
45
45
  /// Drops all per-mount state so the view can be recycled.
46
46
  @objc public func reset() {
47
- markdownUtils = RCTMarcusUtils()
47
+ markdownUtils = MarkdownUtils()
48
48
  }
49
49
 
50
50
  // MARK: - Attach / detach
@@ -48,4 +48,27 @@ extension MarkdownFormatter {
48
48
  fonts: MarkdownReactFonts()
49
49
  )
50
50
  }
51
+
52
+ /// The paragraph entry point. Same formatting, except that whatever the
53
+ /// shadow tree already put on the string -- nested `Text` attributes, inline
54
+ /// view attachments -- is left where it is, and that the list markers are
55
+ /// rendered rather than shown: this is the finished text rather than the text
56
+ /// being written.
57
+ @objc(formatParagraph:defaultTextAttributes:ranges:style:)
58
+ public static func formatParagraph(
59
+ _ attributedString: NSMutableAttributedString,
60
+ defaultTextAttributes: [NSAttributedString.Key: Any],
61
+ ranges: [MarcusRange],
62
+ style: RCTMarcusStyle
63
+ ) {
64
+ format(
65
+ attributedString,
66
+ defaultTextAttributes: defaultTextAttributes,
67
+ ranges: ranges,
68
+ style: style,
69
+ fonts: MarkdownReactFonts(),
70
+ resetAttributes: false,
71
+ display: true
72
+ )
73
+ }
51
74
  }