react-native-marcus 0.1.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 (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +227 -0
  3. package/RNMarcus.podspec +78 -0
  4. package/android/build.gradle +220 -0
  5. package/android/proguard-rules.pro +1 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/AndroidManifestNew.xml +2 -0
  8. package/android/src/main/cpp/CMakeLists.txt +41 -0
  9. package/android/src/main/cpp/MarkdownParser.cpp +49 -0
  10. package/android/src/main/cpp/MarkdownParser.h +56 -0
  11. package/android/src/main/cpp/OnLoad.cpp +17 -0
  12. package/android/src/main/java/app/getbullet/marcus/MarcusModule.kt +28 -0
  13. package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +31 -0
  14. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +63 -0
  15. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManager.kt +32 -0
  16. package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManagerSpec.kt +21 -0
  17. package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +333 -0
  18. package/android/src/main/java/app/getbullet/marcus/MarkdownParseResult.kt +12 -0
  19. package/android/src/main/java/app/getbullet/marcus/MarkdownParser.kt +89 -0
  20. package/android/src/main/java/app/getbullet/marcus/MarkdownRange.kt +11 -0
  21. package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +81 -0
  22. package/android/src/main/java/app/getbullet/marcus/MarkdownTextWatcher.kt +17 -0
  23. package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +84 -0
  24. package/android/src/main/java/app/getbullet/marcus/ReactLineHeight.java +29 -0
  25. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +6 -0
  26. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +105 -0
  27. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +67 -0
  28. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +6 -0
  29. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontFamilySpan.kt +28 -0
  30. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontSizeSpan.kt +7 -0
  31. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownForegroundColorSpan.kt +6 -0
  32. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +57 -0
  33. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +6 -0
  34. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLineHeightSpan.kt +21 -0
  35. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownSpan.kt +7 -0
  36. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownStrikethroughSpan.kt +5 -0
  37. package/android/src/main/java/app/getbullet/marcus/spans/MarkdownUnderlineSpan.kt +5 -0
  38. package/android/src/main/new_arch/CMakeLists.txt +70 -0
  39. package/android/src/main/new_arch/RNMarcusSpec.cpp +43 -0
  40. package/android/src/main/new_arch/RNMarcusSpec.h +36 -0
  41. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.cpp +218 -0
  42. package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.h +54 -0
  43. package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +156 -0
  44. package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +130 -0
  45. package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +205 -0
  46. package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +78 -0
  47. package/android/src/test/resources/render-model.txt +583 -0
  48. package/apple/MarcusModule.h +8 -0
  49. package/apple/MarcusModule.mm +26 -0
  50. package/apple/MarcusRange.h +15 -0
  51. package/apple/MarcusRange.mm +15 -0
  52. package/apple/MarcusTextInputDecoratorComponentView.h +12 -0
  53. package/apple/MarcusTextInputDecoratorComponentView.mm +121 -0
  54. package/apple/MarcusTextInputDecoratorShadowNode.cpp +251 -0
  55. package/apple/MarcusTextInputDecoratorShadowNode.h +65 -0
  56. package/apple/MarcusTextInputDecoratorShadowNode.mm +204 -0
  57. package/apple/MarcusTextInputDecoratorViewManager.h +8 -0
  58. package/apple/MarcusTextInputDecoratorViewManager.mm +11 -0
  59. package/apple/MarkdownAdaptiveImageGlyph.swift +44 -0
  60. package/apple/MarkdownAttributes.h +31 -0
  61. package/apple/MarkdownAttributes.m +9 -0
  62. package/apple/MarkdownBackedTextInputDelegate.swift +117 -0
  63. package/apple/MarkdownDecorator.swift +316 -0
  64. package/apple/MarkdownFonts.swift +21 -0
  65. package/apple/MarkdownFormatter+React.swift +51 -0
  66. package/apple/MarkdownFormatter.swift +509 -0
  67. package/apple/MarkdownLog.h +10 -0
  68. package/apple/MarkdownLog.mm +6 -0
  69. package/apple/MarkdownParser.swift +200 -0
  70. package/apple/MarkdownSwiftInterop.h +23 -0
  71. package/apple/MarkdownTextBackground.swift +17 -0
  72. package/apple/MarkdownTextFieldObserver.swift +90 -0
  73. package/apple/MarkdownTextLayoutFragment.swift +205 -0
  74. package/apple/MarkdownTextLayoutManagerDelegate.swift +84 -0
  75. package/apple/MarkdownTextStorageDelegate.swift +32 -0
  76. package/apple/MarkdownTextViewObserver.swift +30 -0
  77. package/apple/RCTMarcusStyle+Codegen.h +18 -0
  78. package/apple/RCTMarcusStyle+Codegen.mm +64 -0
  79. package/apple/RCTMarcusStyle.h +41 -0
  80. package/apple/RCTMarcusStyle.m +5 -0
  81. package/apple/RCTMarcusUtils.h +26 -0
  82. package/apple/RCTMarcusUtils.mm +26 -0
  83. package/apple/RCTTextInput+AdaptiveImageGlyph.h +16 -0
  84. package/apple/RCTTextInput+AdaptiveImageGlyph.mm +79 -0
  85. package/apple/RCTTextInputComponentView+Marcus.h +11 -0
  86. package/apple/RCTTextInputComponentView+Marcus.mm +79 -0
  87. package/cpp/MarkdownCxx.modulemap +8 -0
  88. package/cpp/MarkdownGlobal.cpp +48 -0
  89. package/cpp/MarkdownGlobal.h +33 -0
  90. package/cpp/MarkdownWorkletParser.cpp +93 -0
  91. package/cpp/MarkdownWorkletParser.h +45 -0
  92. package/cpp/RuntimeDecorator.cpp +39 -0
  93. package/cpp/RuntimeDecorator.h +14 -0
  94. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorState.h +33 -0
  95. package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorViewComponentDescriptor.h +17 -0
  96. package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  97. package/lib/commonjs/MarkdownTextInput.js +99 -0
  98. package/lib/commonjs/MarkdownTextInput.js.map +1 -0
  99. package/lib/commonjs/MarkdownTextInput.web.js +618 -0
  100. package/lib/commonjs/MarkdownTextInput.web.js.map +1 -0
  101. package/lib/commonjs/NativeMarcusModule.js +9 -0
  102. package/lib/commonjs/NativeMarcusModule.js.map +1 -0
  103. package/lib/commonjs/commonTypes.js +2 -0
  104. package/lib/commonjs/commonTypes.js.map +1 -0
  105. package/lib/commonjs/global.d.js +2 -0
  106. package/lib/commonjs/global.d.js.map +1 -0
  107. package/lib/commonjs/index.js +27 -0
  108. package/lib/commonjs/index.js.map +1 -0
  109. package/lib/commonjs/package.json +1 -0
  110. package/lib/commonjs/parser/index.js +7030 -0
  111. package/lib/commonjs/parser/index.js.map +7 -0
  112. package/lib/commonjs/rangeUtils.js +71 -0
  113. package/lib/commonjs/rangeUtils.js.map +1 -0
  114. package/lib/commonjs/react-native-web.d.js +2 -0
  115. package/lib/commonjs/react-native-web.d.js.map +1 -0
  116. package/lib/commonjs/styleUtils.js +91 -0
  117. package/lib/commonjs/styleUtils.js.map +1 -0
  118. package/lib/commonjs/web/InputHistory.js +111 -0
  119. package/lib/commonjs/web/InputHistory.js.map +1 -0
  120. package/lib/commonjs/web/MarkdownTextInput.css +72 -0
  121. package/lib/commonjs/web/utils/blockLayout.js +132 -0
  122. package/lib/commonjs/web/utils/blockLayout.js.map +1 -0
  123. package/lib/commonjs/web/utils/blockUtils.js +219 -0
  124. package/lib/commonjs/web/utils/blockUtils.js.map +1 -0
  125. package/lib/commonjs/web/utils/browserUtils.js +40 -0
  126. package/lib/commonjs/web/utils/browserUtils.js.map +1 -0
  127. package/lib/commonjs/web/utils/cursorUtils.js +157 -0
  128. package/lib/commonjs/web/utils/cursorUtils.js.map +1 -0
  129. package/lib/commonjs/web/utils/inputUtils.js +152 -0
  130. package/lib/commonjs/web/utils/inputUtils.js.map +1 -0
  131. package/lib/commonjs/web/utils/measureUtils.js +0 -0
  132. package/lib/commonjs/web/utils/measureUtils.js.map +1 -0
  133. package/lib/commonjs/web/utils/parserUtils.js +552 -0
  134. package/lib/commonjs/web/utils/parserUtils.js.map +1 -0
  135. package/lib/commonjs/web/utils/treeUtils.js +109 -0
  136. package/lib/commonjs/web/utils/treeUtils.js.map +1 -0
  137. package/lib/commonjs/web/utils/webStyleUtils.js +59 -0
  138. package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -0
  139. package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  140. package/lib/module/MarkdownTextInput.js +94 -0
  141. package/lib/module/MarkdownTextInput.js.map +1 -0
  142. package/lib/module/MarkdownTextInput.web.js +612 -0
  143. package/lib/module/MarkdownTextInput.web.js.map +1 -0
  144. package/lib/module/NativeMarcusModule.js +5 -0
  145. package/lib/module/NativeMarcusModule.js.map +1 -0
  146. package/lib/module/commonTypes.js +2 -0
  147. package/lib/module/commonTypes.js.map +1 -0
  148. package/lib/module/global.d.js +2 -0
  149. package/lib/module/global.d.js.map +1 -0
  150. package/lib/module/index.js +5 -0
  151. package/lib/module/index.js.map +1 -0
  152. package/lib/module/package.json +1 -0
  153. package/lib/module/parser/index.js +7029 -0
  154. package/lib/module/parser/index.js.map +7 -0
  155. package/lib/module/rangeUtils.js +66 -0
  156. package/lib/module/rangeUtils.js.map +1 -0
  157. package/lib/module/react-native-web.d.js +2 -0
  158. package/lib/module/react-native-web.d.js.map +1 -0
  159. package/lib/module/styleUtils.js +88 -0
  160. package/lib/module/styleUtils.js.map +1 -0
  161. package/lib/module/web/InputHistory.js +106 -0
  162. package/lib/module/web/InputHistory.js.map +1 -0
  163. package/lib/module/web/MarkdownTextInput.css +72 -0
  164. package/lib/module/web/utils/blockLayout.js +128 -0
  165. package/lib/module/web/utils/blockLayout.js.map +1 -0
  166. package/lib/module/web/utils/blockUtils.js +210 -0
  167. package/lib/module/web/utils/blockUtils.js.map +1 -0
  168. package/lib/module/web/utils/browserUtils.js +36 -0
  169. package/lib/module/web/utils/browserUtils.js.map +1 -0
  170. package/lib/module/web/utils/cursorUtils.js +150 -0
  171. package/lib/module/web/utils/cursorUtils.js.map +1 -0
  172. package/lib/module/web/utils/inputUtils.js +144 -0
  173. package/lib/module/web/utils/inputUtils.js.map +1 -0
  174. package/lib/module/web/utils/measureUtils.js +0 -0
  175. package/lib/module/web/utils/measureUtils.js.map +1 -0
  176. package/lib/module/web/utils/parserUtils.js +547 -0
  177. package/lib/module/web/utils/parserUtils.js.map +1 -0
  178. package/lib/module/web/utils/treeUtils.js +103 -0
  179. package/lib/module/web/utils/treeUtils.js.map +1 -0
  180. package/lib/module/web/utils/webStyleUtils.js +54 -0
  181. package/lib/module/web/utils/webStyleUtils.js.map +1 -0
  182. package/lib/typescript/commonjs/e2e/checks.test.d.ts +2 -0
  183. package/lib/typescript/commonjs/e2e/checks.test.d.ts.map +1 -0
  184. package/lib/typescript/commonjs/e2e/editing.test.d.ts +2 -0
  185. package/lib/typescript/commonjs/e2e/editing.test.d.ts.map +1 -0
  186. package/lib/typescript/commonjs/e2e/helpers.d.ts +23 -0
  187. package/lib/typescript/commonjs/e2e/helpers.d.ts.map +1 -0
  188. package/lib/typescript/commonjs/e2e/smoke.test.d.ts +2 -0
  189. package/lib/typescript/commonjs/e2e/smoke.test.d.ts.map +1 -0
  190. package/lib/typescript/commonjs/package.json +1 -0
  191. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
  192. package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
  193. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +22 -0
  194. package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -0
  195. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +41 -0
  196. package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts +7 -0
  198. package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts.map +1 -0
  199. package/lib/typescript/commonjs/src/commonTypes.d.ts +10 -0
  200. package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -0
  201. package/lib/typescript/commonjs/src/index.d.ts +5 -0
  202. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  203. package/lib/typescript/commonjs/src/parser/index.d.ts +8 -0
  204. package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -0
  205. package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts +8 -0
  206. package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -0
  207. package/lib/typescript/commonjs/src/rangeUtils.d.ts +6 -0
  208. package/lib/typescript/commonjs/src/rangeUtils.d.ts.map +1 -0
  209. package/lib/typescript/commonjs/src/styleUtils.d.ts +8 -0
  210. package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -0
  211. package/lib/typescript/commonjs/src/web/InputHistory.d.ts +24 -0
  212. package/lib/typescript/commonjs/src/web/InputHistory.d.ts.map +1 -0
  213. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +41 -0
  214. package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -0
  215. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +33 -0
  216. package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -0
  217. package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts +7 -0
  218. package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts.map +1 -0
  219. package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts +12 -0
  220. package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts.map +1 -0
  221. package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts +12 -0
  222. package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts.map +1 -0
  223. package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts +22 -0
  224. package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts.map +1 -0
  225. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +44 -0
  226. package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -0
  227. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +25 -0
  228. package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -0
  229. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +7 -0
  230. package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -0
  231. package/lib/typescript/module/e2e/checks.test.d.ts +2 -0
  232. package/lib/typescript/module/e2e/checks.test.d.ts.map +1 -0
  233. package/lib/typescript/module/e2e/editing.test.d.ts +2 -0
  234. package/lib/typescript/module/e2e/editing.test.d.ts.map +1 -0
  235. package/lib/typescript/module/e2e/helpers.d.ts +23 -0
  236. package/lib/typescript/module/e2e/helpers.d.ts.map +1 -0
  237. package/lib/typescript/module/e2e/smoke.test.d.ts +2 -0
  238. package/lib/typescript/module/e2e/smoke.test.d.ts.map +1 -0
  239. package/lib/typescript/module/package.json +1 -0
  240. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
  241. package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
  242. package/lib/typescript/module/src/MarkdownTextInput.d.ts +22 -0
  243. package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -0
  244. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +41 -0
  245. package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -0
  246. package/lib/typescript/module/src/NativeMarcusModule.d.ts +7 -0
  247. package/lib/typescript/module/src/NativeMarcusModule.d.ts.map +1 -0
  248. package/lib/typescript/module/src/commonTypes.d.ts +10 -0
  249. package/lib/typescript/module/src/commonTypes.d.ts.map +1 -0
  250. package/lib/typescript/module/src/index.d.ts +5 -0
  251. package/lib/typescript/module/src/index.d.ts.map +1 -0
  252. package/lib/typescript/module/src/parser/index.d.ts +8 -0
  253. package/lib/typescript/module/src/parser/index.d.ts.map +1 -0
  254. package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts +8 -0
  255. package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -0
  256. package/lib/typescript/module/src/rangeUtils.d.ts +6 -0
  257. package/lib/typescript/module/src/rangeUtils.d.ts.map +1 -0
  258. package/lib/typescript/module/src/styleUtils.d.ts +8 -0
  259. package/lib/typescript/module/src/styleUtils.d.ts.map +1 -0
  260. package/lib/typescript/module/src/web/InputHistory.d.ts +24 -0
  261. package/lib/typescript/module/src/web/InputHistory.d.ts.map +1 -0
  262. package/lib/typescript/module/src/web/utils/blockLayout.d.ts +41 -0
  263. package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -0
  264. package/lib/typescript/module/src/web/utils/blockUtils.d.ts +33 -0
  265. package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -0
  266. package/lib/typescript/module/src/web/utils/browserUtils.d.ts +7 -0
  267. package/lib/typescript/module/src/web/utils/browserUtils.d.ts.map +1 -0
  268. package/lib/typescript/module/src/web/utils/cursorUtils.d.ts +12 -0
  269. package/lib/typescript/module/src/web/utils/cursorUtils.d.ts.map +1 -0
  270. package/lib/typescript/module/src/web/utils/inputUtils.d.ts +12 -0
  271. package/lib/typescript/module/src/web/utils/inputUtils.d.ts.map +1 -0
  272. package/lib/typescript/module/src/web/utils/measureUtils.d.ts +22 -0
  273. package/lib/typescript/module/src/web/utils/measureUtils.d.ts.map +1 -0
  274. package/lib/typescript/module/src/web/utils/parserUtils.d.ts +44 -0
  275. package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -0
  276. package/lib/typescript/module/src/web/utils/treeUtils.d.ts +25 -0
  277. package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -0
  278. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +7 -0
  279. package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -0
  280. package/package.json +167 -0
  281. package/react-native.config.js +10 -0
  282. package/src/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
  283. package/src/MarkdownTextInput.tsx +139 -0
  284. package/src/MarkdownTextInput.web.tsx +958 -0
  285. package/src/NativeMarcusModule.ts +8 -0
  286. package/src/commonTypes.ts +30 -0
  287. package/src/global.d.ts +1 -0
  288. package/src/index.tsx +4 -0
  289. package/src/parser/index.ts +556 -0
  290. package/src/parser/micromark-extension-mentions.ts +82 -0
  291. package/src/rangeUtils.ts +68 -0
  292. package/src/react-native-web.d.ts +1 -0
  293. package/src/styleUtils.ts +100 -0
  294. package/src/web/InputHistory.ts +137 -0
  295. package/src/web/MarkdownTextInput.css +72 -0
  296. package/src/web/utils/blockLayout.ts +163 -0
  297. package/src/web/utils/blockUtils.ts +245 -0
  298. package/src/web/utils/browserUtils.ts +41 -0
  299. package/src/web/utils/cursorUtils.ts +204 -0
  300. package/src/web/utils/inputUtils.ts +206 -0
  301. package/src/web/utils/measureUtils.ts +0 -0
  302. package/src/web/utils/parserUtils.ts +813 -0
  303. package/src/web/utils/treeUtils.ts +149 -0
  304. package/src/web/utils/webStyleUtils.ts +69 -0
@@ -0,0 +1,218 @@
1
+ #include "MarcusTextInputDecoratorShadowNode.h"
2
+
3
+ #include <fbjni/fbjni.h>
4
+ #include <react/fabric/JFabricUIManager.h>
5
+ #include <react/jni/ReadableNativeMap.h>
6
+ #if REACT_NATIVE_MINOR_VERSION < 80
7
+ #include <react/jni/SafeReleaseJniRef.h>
8
+ #endif // REACT_NATIVE_MINOR_VERSION < 80
9
+ #include <react/renderer/components/view/conversions.h>
10
+ #include <react/renderer/core/ComponentDescriptor.h>
11
+ #include <yoga/Yoga.h>
12
+
13
+ namespace facebook {
14
+ namespace react {
15
+
16
+ extern const char MarcusTextInputDecoratorViewComponentName[] =
17
+ "MarcusTextInputDecoratorView";
18
+
19
+ MarcusTextInputDecoratorShadowNode::MarcusTextInputDecoratorShadowNode(
20
+ ShadowNodeFragment const &fragment, ShadowNodeFamily::Shared const &family, ShadowNodeTraits traits
21
+ )
22
+ : ConcreteViewShadowNode(fragment, family, traits) {
23
+ initialize();
24
+ createCustomContextContainer();
25
+ makeChildNodeMutable();
26
+
27
+ if (fragment.children) {
28
+ overwriteTextLayoutManager();
29
+ }
30
+ }
31
+
32
+ MarcusTextInputDecoratorShadowNode::MarcusTextInputDecoratorShadowNode(
33
+ ShadowNode const &sourceShadowNode, ShadowNodeFragment const &fragment
34
+ )
35
+ : ConcreteViewShadowNode(sourceShadowNode, fragment) {
36
+ initialize();
37
+
38
+ const auto &sourceDecorator =
39
+ static_cast<const MarcusTextInputDecoratorShadowNode &>(
40
+ sourceShadowNode
41
+ );
42
+
43
+ customContextContainer_ = sourceDecorator.customContextContainer_;
44
+ previousMarkdownStyle_ = sourceDecorator.previousMarkdownStyle_;
45
+ previousParserId_ = sourceDecorator.previousParserId_;
46
+
47
+ updateCustomContextContainerIfNeeded();
48
+ makeChildNodeMutable();
49
+
50
+ if (fragment.children) {
51
+ overwriteTextLayoutManager();
52
+ }
53
+ }
54
+
55
+ void
56
+ MarcusTextInputDecoratorShadowNode::initialize() {
57
+ // Setting display: contents style results in ForceFlattenView trait being set
58
+ // on the shadow node. This trait causes the node not to have a host view. By
59
+ // removing the trait, it's possible to force RN to create a host view, layout
60
+ // of which can then be customized.
61
+ ShadowNode::traits_.unset(ShadowNodeTraits::ForceFlattenView);
62
+ }
63
+
64
+ void
65
+ MarcusTextInputDecoratorShadowNode::makeChildNodeMutable() {
66
+ // When the decorator is cloned and has a child node, the child node should be
67
+ // cloned as well to ensure it is mutable.
68
+ const auto &children = getChildren();
69
+ if (!children.empty()) {
70
+ react_native_assert(
71
+ children.size() == 1 &&
72
+ "MarcusTextInputDecoratorView received more than one child"
73
+ );
74
+
75
+ const auto clonedChild = children[0]->clone({});
76
+ replaceChild(*children[0], clonedChild);
77
+ }
78
+ }
79
+
80
+ void
81
+ MarcusTextInputDecoratorShadowNode::createCustomContextContainer() {
82
+ static const auto customFabricUIManagerClass =
83
+ jni::findClassStatic("app/getbullet/marcus/CustomFabricUIManager");
84
+ static const auto createMethod =
85
+ customFabricUIManagerClass->getStaticMethod<JFabricUIManager::javaobject(
86
+ JFabricUIManager::javaobject, ReadableMap::javaobject, int
87
+ )>(
88
+ "create"
89
+ );
90
+
91
+ const auto &rawProps = this->getProps()->rawProps;
92
+ const auto &markdownStyleIt = rawProps.find("markdownStyle");
93
+ const auto &markdownStyle = markdownStyleIt != rawProps.items().end()
94
+ ? markdownStyleIt->second
95
+ : previousMarkdownStyle_;
96
+ const auto &parserIdIt = rawProps.find("parserId");
97
+ const auto parserId = parserIdIt != rawProps.items().end()
98
+ ? parserIdIt->second.asInt()
99
+ : previousParserId_;
100
+
101
+ const auto decoratorPropsRNM =
102
+ ReadableNativeMap::newObjectCxxArgs(markdownStyle);
103
+ const auto decoratorPropsRM = jni::make_local(
104
+ reinterpret_cast<ReadableMap::javaobject>(decoratorPropsRNM.get())
105
+ );
106
+
107
+ const auto &fabricUIManager =
108
+ this->getContextContainer()->at<JFabricUIManager::javaobject>(
109
+ "FabricUIManager"
110
+ );
111
+
112
+ const auto customFabricUIManager = SafeReleaseJniRef(
113
+ jni::make_global(createMethod(customFabricUIManagerClass, fabricUIManager, decoratorPropsRM.get(), parserId))
114
+ );
115
+ const auto contextContainer = std::make_shared<ContextContainer const>();
116
+ contextContainer->insert("FabricUIManager", customFabricUIManager);
117
+
118
+ customContextContainer_ = contextContainer;
119
+ previousMarkdownStyle_ = markdownStyle;
120
+ previousParserId_ = parserId;
121
+ }
122
+
123
+ void
124
+ MarcusTextInputDecoratorShadowNode::
125
+ updateCustomContextContainerIfNeeded() {
126
+ const auto &rawProps = this->getProps()->rawProps;
127
+ const auto &markdownStyleIt = rawProps.find("markdownStyle");
128
+ if (markdownStyleIt != rawProps.items().end() &&
129
+ markdownStyleIt->second != previousMarkdownStyle_) {
130
+ createCustomContextContainer();
131
+ return;
132
+ }
133
+ const auto &parserIdIt = rawProps.find("parserId");
134
+ if (parserIdIt != rawProps.items().end() &&
135
+ parserIdIt->second.asInt() != previousParserId_) {
136
+ createCustomContextContainer();
137
+ }
138
+ }
139
+
140
+ void
141
+ MarcusTextInputDecoratorShadowNode::overwriteTextLayoutManager() {
142
+ const auto &children = getChildren();
143
+ if (children.empty()) {
144
+ return;
145
+ }
146
+ react_native_assert(
147
+ children.size() == 1 &&
148
+ "MarcusTextInputDecoratorView received more than one child"
149
+ );
150
+
151
+ const auto child =
152
+ std::dynamic_pointer_cast<const AndroidTextInputShadowNode>(children[0]);
153
+
154
+ react_native_assert(
155
+ child != nullptr &&
156
+ "MarcusTextInputDecoratorView received child other than a TextInput"
157
+ );
158
+ child->ensureUnsealed();
159
+
160
+ const auto mutableChild =
161
+ std::const_pointer_cast<AndroidTextInputShadowNode>(child);
162
+ mutableChild->setTextLayoutManager(
163
+ std::make_shared<TextLayoutManager>(customContextContainer_)
164
+ );
165
+ }
166
+
167
+ void
168
+ MarcusTextInputDecoratorShadowNode::appendChild(
169
+ const std::shared_ptr<const ShadowNode> &child
170
+ ) {
171
+ YogaLayoutableShadowNode::appendChild(child);
172
+
173
+ overwriteTextLayoutManager();
174
+ }
175
+
176
+ void
177
+ MarcusTextInputDecoratorShadowNode::replaceChild(
178
+ const ShadowNode &oldChild,
179
+ const std::shared_ptr<const ShadowNode> &newChild,
180
+ size_t suggestedIndex
181
+ ) {
182
+ YogaLayoutableShadowNode::replaceChild(oldChild, newChild, suggestedIndex);
183
+
184
+ overwriteTextLayoutManager();
185
+ }
186
+
187
+ void
188
+ MarcusTextInputDecoratorShadowNode::layout(LayoutContext layoutContext) {
189
+ YogaLayoutableShadowNode::layout(layoutContext);
190
+
191
+ const auto &children = getChildren();
192
+ react_native_assert(
193
+ children.size() == 1 &&
194
+ "MarcusTextInputDecoratorView didn't receive exactly one child"
195
+ );
196
+
197
+ auto child =
198
+ std::static_pointer_cast<const YogaLayoutableShadowNode>(children[0]);
199
+ child->ensureUnsealed();
200
+ auto mutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(child);
201
+
202
+ // TODO: this may not be the correct way to do this
203
+ // Since nodes with display: contents are skipped during layout, they have
204
+ // zero-layout. To properly display the view, assign the layout metrics from
205
+ // the child (text input, which was calculated by Yoga) to the decorator view.
206
+ auto childMetrics = child->getLayoutMetrics();
207
+ setLayoutMetrics(childMetrics); // makes a copy
208
+
209
+ // Then, it's also needed to update the metrics on the child as the position
210
+ // is relative to the parent, which was just moved above. By zeroing the
211
+ // origin, the child is effectively moved to the same position it was before
212
+ // the manipulation here.
213
+ childMetrics.frame.origin = Point{};
214
+ mutableChild->setLayoutMetrics(childMetrics);
215
+ }
216
+
217
+ } // namespace react
218
+ } // namespace facebook
@@ -0,0 +1,54 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/components/RNMarcusSpec/EventEmitters.h>
4
+ #include <react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorState.h>
5
+ #include <react/renderer/components/RNMarcusSpec/Props.h>
6
+ #include <react/renderer/components/androidtextinput/AndroidTextInputShadowNode.h>
7
+
8
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
9
+ #include <react/renderer/core/LayoutContext.h>
10
+
11
+ namespace facebook {
12
+ namespace react {
13
+
14
+ JSI_EXPORT extern const char MarcusTextInputDecoratorViewComponentName[];
15
+
16
+ class JSI_EXPORT MarcusTextInputDecoratorShadowNode final
17
+ : public ConcreteViewShadowNode<MarcusTextInputDecoratorViewComponentName, MarcusTextInputDecoratorViewProps, MarcusTextInputDecoratorViewEventEmitter, MarcusTextInputDecoratorState> {
18
+ public:
19
+ MarcusTextInputDecoratorShadowNode(ShadowNodeFragment const &fragment, ShadowNodeFamily::Shared const &family, ShadowNodeTraits traits);
20
+
21
+ MarcusTextInputDecoratorShadowNode(ShadowNode const &sourceShadowNode, ShadowNodeFragment const &fragment);
22
+
23
+ void
24
+ appendChild(const std::shared_ptr<const ShadowNode> &child) override;
25
+
26
+ void
27
+ replaceChild(const ShadowNode &oldChild, const std::shared_ptr<const ShadowNode> &newChild, size_t suggestedIndex = SIZE_MAX) override;
28
+
29
+ void
30
+ layout(LayoutContext layoutContext) override;
31
+
32
+ private:
33
+ std::shared_ptr<const ContextContainer> customContextContainer_;
34
+ folly::dynamic previousMarkdownStyle_;
35
+ int previousParserId_;
36
+
37
+ void
38
+ initialize();
39
+
40
+ void
41
+ overwriteTextLayoutManager();
42
+
43
+ void
44
+ createCustomContextContainer();
45
+
46
+ void
47
+ updateCustomContextContainerIfNeeded();
48
+
49
+ void
50
+ makeChildNodeMutable();
51
+ };
52
+
53
+ } // namespace react
54
+ } // namespace facebook
@@ -0,0 +1,156 @@
1
+ package app.getbullet.marcus;
2
+
3
+ /*
4
+ * NOTE: This file deliberately stays in Java.
5
+ *
6
+ * Everything it does sits on React Native declarations that are `internal` in Kotlin:
7
+ * `TextLayoutManager` (the measureText call itself), `LayoutMetricsConversions`
8
+ * (getYogaSize / getYogaMeasureMode) and `MountingManager`, which is both a constructor
9
+ * parameter type and a field type here. Java still sees all of them because `internal`
10
+ * stays public in the bytecode; the Kotlin compiler refuses.
11
+ *
12
+ * A Kotlin version would have to smuggle MountingManager as `Any` and delegate the whole
13
+ * method body to a Java helper, which is more indirection for no gain, so the class is
14
+ * left as-is until React Native opens these APIs up.
15
+ */
16
+
17
+ import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode;
18
+ import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaSize;
19
+
20
+ import android.text.SpannableStringBuilder;
21
+
22
+ import androidx.annotation.Nullable;
23
+
24
+ import com.facebook.infer.annotation.Assertions;
25
+ import com.facebook.jni.annotations.DoNotStrip;
26
+ import com.facebook.react.bridge.ReactApplicationContext;
27
+ import com.facebook.react.bridge.ReactContext;
28
+ import com.facebook.react.bridge.ReadableMap;
29
+ import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
30
+ import com.facebook.react.fabric.FabricUIManager;
31
+ import com.facebook.react.fabric.mounting.MountingManager;
32
+ import com.facebook.react.fabric.mounting.SurfaceMountingManager;
33
+ import com.facebook.react.uimanager.ViewManagerRegistry;
34
+ import com.facebook.react.uimanager.events.BatchEventDispatchedListener;
35
+ import com.facebook.react.views.text.TextLayoutManager;
36
+
37
+ import java.lang.reflect.Field;
38
+
39
+ @DoNotStrip
40
+ public class CustomFabricUIManager extends FabricUIManager {
41
+
42
+ private final ReactApplicationContext mReactApplicationContext;
43
+ private final MountingManager mMountingManager;
44
+ private final MarkdownUtils mMarkdownUtils;
45
+
46
+ public CustomFabricUIManager(
47
+ ReactApplicationContext reactContext,
48
+ ViewManagerRegistry viewManagerRegistry,
49
+ BatchEventDispatchedListener batchEventDispatchedListener,
50
+ MountingManager mountingManager,
51
+ ReadableMap markdownProps,
52
+ int parserId
53
+ ) {
54
+ super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
55
+
56
+ this.mReactApplicationContext = reactContext;
57
+ this.mMountingManager = mountingManager;
58
+
59
+ this.mMarkdownUtils = new MarkdownUtils(reactContext);
60
+ this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
61
+ this.mMarkdownUtils.setParserId(parserId);
62
+ }
63
+
64
+ @Override
65
+ public long measureText(
66
+ int surfaceId,
67
+ ReadableMapBuffer attributedString,
68
+ ReadableMapBuffer paragraphAttributes,
69
+ float minWidth,
70
+ float maxWidth,
71
+ float minHeight,
72
+ float maxHeight,
73
+ @Nullable float[] attachmentsPositions) {
74
+
75
+ ReactContext context;
76
+ if (surfaceId > 0) {
77
+ SurfaceMountingManager surfaceMountingManager =
78
+ mMountingManager.getSurfaceManagerEnforced(surfaceId, "measureText");
79
+ if (surfaceMountingManager.isStopped()) {
80
+ return 0;
81
+ }
82
+ context = surfaceMountingManager.getContext();
83
+ Assertions.assertNotNull(
84
+ context, "Context in SurfaceMountingManager is null. surfaceId: " + surfaceId);
85
+ } else {
86
+ context = mReactApplicationContext;
87
+ }
88
+
89
+ return TextLayoutManager.measureText(
90
+ context,
91
+ attributedString,
92
+ paragraphAttributes,
93
+ getYogaSize(minWidth, maxWidth),
94
+ getYogaMeasureMode(minWidth, maxWidth),
95
+ getYogaSize(minHeight, maxHeight),
96
+ getYogaMeasureMode(minHeight, maxHeight),
97
+ spannable -> {
98
+ mMarkdownUtils.applyMarkdownFormatting((SpannableStringBuilder) spannable);
99
+ },
100
+ attachmentsPositions);
101
+ }
102
+
103
+ public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
104
+ try {
105
+ MountingManager sourceMountingManager = readPrivateField(source, "mMountingManager");
106
+ ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
107
+ ViewManagerRegistry viewManagerRegistry = readPrivateField(source, "mViewManagerRegistry");
108
+ BatchEventDispatchedListener batchEventDispatchedListener = readPrivateField(source, "mBatchEventDispatchedListener");
109
+
110
+ FabricUIManager customFabricUIManager = new CustomFabricUIManager(
111
+ reactContext,
112
+ viewManagerRegistry,
113
+ batchEventDispatchedListener,
114
+ sourceMountingManager,
115
+ markdownProps,
116
+ parserId
117
+ );
118
+
119
+ return customFabricUIManager;
120
+ } catch (NoSuchFieldException | IllegalAccessException e) {
121
+ throw new RuntimeException("[Marcus] Cannot read data from FabricUIManager", e);
122
+ }
123
+ }
124
+
125
+ @SuppressWarnings("unchecked")
126
+ private static <T> T readPrivateField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
127
+ Class<?> clazz = obj.getClass();
128
+
129
+ Field field;
130
+ try {
131
+ field = clazz.getDeclaredField(name);
132
+ } catch (NoSuchFieldException e) {
133
+ // FabricUIManager is one of the last Java files left in React Native's fabric
134
+ // package. When it is converted to Kotlin these `m`-prefixed names go away, and a
135
+ // bare NoSuchFieldException gives no hint why. Name what we actually found.
136
+ StringBuilder declared = new StringBuilder();
137
+ for (Field candidate : clazz.getDeclaredFields()) {
138
+ if (declared.length() > 0) {
139
+ declared.append(", ");
140
+ }
141
+ declared.append(candidate.getName());
142
+ }
143
+ throw new NoSuchFieldException(
144
+ "[Marcus] "
145
+ + clazz.getName()
146
+ + " has no field '"
147
+ + name
148
+ + "'. React Native most likely renamed it. Declared fields: "
149
+ + declared);
150
+ }
151
+ field.setAccessible(true);
152
+ T value = (T) field.get(obj);
153
+
154
+ return value;
155
+ }
156
+ }
@@ -0,0 +1,130 @@
1
+ package app.getbullet.marcus;
2
+
3
+ /*
4
+ * NOTE: This file deliberately stays in Java.
5
+ *
6
+ * Everything it does sits on React Native declarations that are `internal` in Kotlin:
7
+ * `TextLayoutManager` (the measureText call itself), `LayoutMetricsConversions`
8
+ * (getYogaSize / getYogaMeasureMode) and `MountingManager`, which is both a constructor
9
+ * parameter type and a field type here. Java still sees all of them because `internal`
10
+ * stays public in the bytecode; the Kotlin compiler refuses.
11
+ *
12
+ * A Kotlin version would have to smuggle MountingManager as `Any` and delegate the whole
13
+ * method body to a Java helper, which is more indirection for no gain, so the class is
14
+ * left as-is until React Native opens these APIs up.
15
+ */
16
+
17
+ import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaMeasureMode;
18
+ import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getYogaSize;
19
+
20
+ import android.text.SpannableStringBuilder;
21
+
22
+ import androidx.annotation.Nullable;
23
+
24
+ import com.facebook.jni.annotations.DoNotStrip;
25
+ import com.facebook.react.bridge.ReactApplicationContext;
26
+ import com.facebook.react.bridge.ReadableMap;
27
+ import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
28
+ import com.facebook.react.fabric.FabricUIManager;
29
+ import com.facebook.react.uimanager.ViewManagerRegistry;
30
+ import com.facebook.react.uimanager.events.BatchEventDispatchedListener;
31
+ import com.facebook.react.views.text.TextLayoutManager;
32
+
33
+ import java.lang.reflect.Field;
34
+
35
+ @DoNotStrip
36
+ public class CustomFabricUIManager extends FabricUIManager {
37
+
38
+ private final ReactApplicationContext mReactApplicationContext;
39
+ private final MarkdownUtils mMarkdownUtils;
40
+
41
+ public CustomFabricUIManager(
42
+ ReactApplicationContext reactContext,
43
+ ViewManagerRegistry viewManagerRegistry,
44
+ BatchEventDispatchedListener batchEventDispatchedListener,
45
+ ReadableMap markdownProps,
46
+ int parserId
47
+ ) {
48
+ super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
49
+
50
+ this.mReactApplicationContext = reactContext;
51
+
52
+ this.mMarkdownUtils = new MarkdownUtils(reactContext);
53
+ this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
54
+ this.mMarkdownUtils.setParserId(parserId);
55
+ }
56
+
57
+ @Override
58
+ public long measureText(
59
+ ReadableMapBuffer attributedString,
60
+ ReadableMapBuffer paragraphAttributes,
61
+ float minWidth,
62
+ float maxWidth,
63
+ float minHeight,
64
+ float maxHeight,
65
+ @Nullable float[] attachmentsPositions) {
66
+
67
+ return TextLayoutManager.measureText(
68
+ mReactApplicationContext.getAssets(),
69
+ attributedString,
70
+ paragraphAttributes,
71
+ getYogaSize(minWidth, maxWidth),
72
+ getYogaMeasureMode(minWidth, maxWidth),
73
+ getYogaSize(minHeight, maxHeight),
74
+ getYogaMeasureMode(minHeight, maxHeight),
75
+ spannable -> {
76
+ mMarkdownUtils.applyMarkdownFormatting((SpannableStringBuilder)spannable);
77
+ },
78
+ attachmentsPositions);
79
+ }
80
+
81
+ public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
82
+ try {
83
+ ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
84
+ ViewManagerRegistry viewManagerRegistry = readPrivateField(source, "mViewManagerRegistry");
85
+ BatchEventDispatchedListener batchEventDispatchedListener = readPrivateField(source, "mBatchEventDispatchedListener");
86
+
87
+ return new CustomFabricUIManager(
88
+ reactContext,
89
+ viewManagerRegistry,
90
+ batchEventDispatchedListener,
91
+ markdownProps,
92
+ parserId
93
+ );
94
+ } catch (NoSuchFieldException | IllegalAccessException e) {
95
+ throw new RuntimeException("[Marcus] Cannot read data from FabricUIManager", e);
96
+ }
97
+ }
98
+
99
+ @SuppressWarnings("unchecked")
100
+ private static <T> T readPrivateField(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
101
+ Class<?> clazz = obj.getClass();
102
+
103
+ Field field;
104
+ try {
105
+ field = clazz.getDeclaredField(name);
106
+ } catch (NoSuchFieldException e) {
107
+ // FabricUIManager is one of the last Java files left in React Native's fabric
108
+ // package. When it is converted to Kotlin these `m`-prefixed names go away, and a
109
+ // bare NoSuchFieldException gives no hint why. Name what we actually found.
110
+ StringBuilder declared = new StringBuilder();
111
+ for (Field candidate : clazz.getDeclaredFields()) {
112
+ if (declared.length() > 0) {
113
+ declared.append(", ");
114
+ }
115
+ declared.append(candidate.getName());
116
+ }
117
+ throw new NoSuchFieldException(
118
+ "[Marcus] "
119
+ + clazz.getName()
120
+ + " has no field '"
121
+ + name
122
+ + "'. React Native most likely renamed it. Declared fields: "
123
+ + declared);
124
+ }
125
+ field.setAccessible(true);
126
+ T value = (T) field.get(obj);
127
+
128
+ return value;
129
+ }
130
+ }