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.
- package/LICENSE +201 -0
- package/README.md +227 -0
- package/RNMarcus.podspec +78 -0
- package/android/build.gradle +220 -0
- package/android/proguard-rules.pro +1 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/AndroidManifestNew.xml +2 -0
- package/android/src/main/cpp/CMakeLists.txt +41 -0
- package/android/src/main/cpp/MarkdownParser.cpp +49 -0
- package/android/src/main/cpp/MarkdownParser.h +56 -0
- package/android/src/main/cpp/OnLoad.cpp +17 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusModule.kt +28 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +31 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +63 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManager.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorViewManagerSpec.kt +21 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +333 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownParseResult.kt +12 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownParser.kt +89 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownRange.kt +11 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +81 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownTextWatcher.kt +17 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +84 -0
- package/android/src/main/java/app/getbullet/marcus/ReactLineHeight.java +29 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +105 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +67 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontFamilySpan.kt +28 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontSizeSpan.kt +7 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownForegroundColorSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +57 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +6 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLineHeightSpan.kt +21 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownSpan.kt +7 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownStrikethroughSpan.kt +5 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownUnderlineSpan.kt +5 -0
- package/android/src/main/new_arch/CMakeLists.txt +70 -0
- package/android/src/main/new_arch/RNMarcusSpec.cpp +43 -0
- package/android/src/main/new_arch/RNMarcusSpec.h +36 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.cpp +218 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorShadowNode.h +54 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +156 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +130 -0
- package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +205 -0
- package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +78 -0
- package/android/src/test/resources/render-model.txt +583 -0
- package/apple/MarcusModule.h +8 -0
- package/apple/MarcusModule.mm +26 -0
- package/apple/MarcusRange.h +15 -0
- package/apple/MarcusRange.mm +15 -0
- package/apple/MarcusTextInputDecoratorComponentView.h +12 -0
- package/apple/MarcusTextInputDecoratorComponentView.mm +121 -0
- package/apple/MarcusTextInputDecoratorShadowNode.cpp +251 -0
- package/apple/MarcusTextInputDecoratorShadowNode.h +65 -0
- package/apple/MarcusTextInputDecoratorShadowNode.mm +204 -0
- package/apple/MarcusTextInputDecoratorViewManager.h +8 -0
- package/apple/MarcusTextInputDecoratorViewManager.mm +11 -0
- package/apple/MarkdownAdaptiveImageGlyph.swift +44 -0
- package/apple/MarkdownAttributes.h +31 -0
- package/apple/MarkdownAttributes.m +9 -0
- package/apple/MarkdownBackedTextInputDelegate.swift +117 -0
- package/apple/MarkdownDecorator.swift +316 -0
- package/apple/MarkdownFonts.swift +21 -0
- package/apple/MarkdownFormatter+React.swift +51 -0
- package/apple/MarkdownFormatter.swift +509 -0
- package/apple/MarkdownLog.h +10 -0
- package/apple/MarkdownLog.mm +6 -0
- package/apple/MarkdownParser.swift +200 -0
- package/apple/MarkdownSwiftInterop.h +23 -0
- package/apple/MarkdownTextBackground.swift +17 -0
- package/apple/MarkdownTextFieldObserver.swift +90 -0
- package/apple/MarkdownTextLayoutFragment.swift +205 -0
- package/apple/MarkdownTextLayoutManagerDelegate.swift +84 -0
- package/apple/MarkdownTextStorageDelegate.swift +32 -0
- package/apple/MarkdownTextViewObserver.swift +30 -0
- package/apple/RCTMarcusStyle+Codegen.h +18 -0
- package/apple/RCTMarcusStyle+Codegen.mm +64 -0
- package/apple/RCTMarcusStyle.h +41 -0
- package/apple/RCTMarcusStyle.m +5 -0
- package/apple/RCTMarcusUtils.h +26 -0
- package/apple/RCTMarcusUtils.mm +26 -0
- package/apple/RCTTextInput+AdaptiveImageGlyph.h +16 -0
- package/apple/RCTTextInput+AdaptiveImageGlyph.mm +79 -0
- package/apple/RCTTextInputComponentView+Marcus.h +11 -0
- package/apple/RCTTextInputComponentView+Marcus.mm +79 -0
- package/cpp/MarkdownCxx.modulemap +8 -0
- package/cpp/MarkdownGlobal.cpp +48 -0
- package/cpp/MarkdownGlobal.h +33 -0
- package/cpp/MarkdownWorkletParser.cpp +93 -0
- package/cpp/MarkdownWorkletParser.h +45 -0
- package/cpp/RuntimeDecorator.cpp +39 -0
- package/cpp/RuntimeDecorator.h +14 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorState.h +33 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextInputDecoratorViewComponentDescriptor.h +17 -0
- package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/lib/commonjs/MarkdownTextInput.js +99 -0
- package/lib/commonjs/MarkdownTextInput.js.map +1 -0
- package/lib/commonjs/MarkdownTextInput.web.js +618 -0
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -0
- package/lib/commonjs/NativeMarcusModule.js +9 -0
- package/lib/commonjs/NativeMarcusModule.js.map +1 -0
- package/lib/commonjs/commonTypes.js +2 -0
- package/lib/commonjs/commonTypes.js.map +1 -0
- package/lib/commonjs/global.d.js +2 -0
- package/lib/commonjs/global.d.js.map +1 -0
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/parser/index.js +7030 -0
- package/lib/commonjs/parser/index.js.map +7 -0
- package/lib/commonjs/rangeUtils.js +71 -0
- package/lib/commonjs/rangeUtils.js.map +1 -0
- package/lib/commonjs/react-native-web.d.js +2 -0
- package/lib/commonjs/react-native-web.d.js.map +1 -0
- package/lib/commonjs/styleUtils.js +91 -0
- package/lib/commonjs/styleUtils.js.map +1 -0
- package/lib/commonjs/web/InputHistory.js +111 -0
- package/lib/commonjs/web/InputHistory.js.map +1 -0
- package/lib/commonjs/web/MarkdownTextInput.css +72 -0
- package/lib/commonjs/web/utils/blockLayout.js +132 -0
- package/lib/commonjs/web/utils/blockLayout.js.map +1 -0
- package/lib/commonjs/web/utils/blockUtils.js +219 -0
- package/lib/commonjs/web/utils/blockUtils.js.map +1 -0
- package/lib/commonjs/web/utils/browserUtils.js +40 -0
- package/lib/commonjs/web/utils/browserUtils.js.map +1 -0
- package/lib/commonjs/web/utils/cursorUtils.js +157 -0
- package/lib/commonjs/web/utils/cursorUtils.js.map +1 -0
- package/lib/commonjs/web/utils/inputUtils.js +152 -0
- package/lib/commonjs/web/utils/inputUtils.js.map +1 -0
- package/lib/commonjs/web/utils/measureUtils.js +0 -0
- package/lib/commonjs/web/utils/measureUtils.js.map +1 -0
- package/lib/commonjs/web/utils/parserUtils.js +552 -0
- package/lib/commonjs/web/utils/parserUtils.js.map +1 -0
- package/lib/commonjs/web/utils/treeUtils.js +109 -0
- package/lib/commonjs/web/utils/treeUtils.js.map +1 -0
- package/lib/commonjs/web/utils/webStyleUtils.js +59 -0
- package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -0
- package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/lib/module/MarkdownTextInput.js +94 -0
- package/lib/module/MarkdownTextInput.js.map +1 -0
- package/lib/module/MarkdownTextInput.web.js +612 -0
- package/lib/module/MarkdownTextInput.web.js.map +1 -0
- package/lib/module/NativeMarcusModule.js +5 -0
- package/lib/module/NativeMarcusModule.js.map +1 -0
- package/lib/module/commonTypes.js +2 -0
- package/lib/module/commonTypes.js.map +1 -0
- package/lib/module/global.d.js +2 -0
- package/lib/module/global.d.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/parser/index.js +7029 -0
- package/lib/module/parser/index.js.map +7 -0
- package/lib/module/rangeUtils.js +66 -0
- package/lib/module/rangeUtils.js.map +1 -0
- package/lib/module/react-native-web.d.js +2 -0
- package/lib/module/react-native-web.d.js.map +1 -0
- package/lib/module/styleUtils.js +88 -0
- package/lib/module/styleUtils.js.map +1 -0
- package/lib/module/web/InputHistory.js +106 -0
- package/lib/module/web/InputHistory.js.map +1 -0
- package/lib/module/web/MarkdownTextInput.css +72 -0
- package/lib/module/web/utils/blockLayout.js +128 -0
- package/lib/module/web/utils/blockLayout.js.map +1 -0
- package/lib/module/web/utils/blockUtils.js +210 -0
- package/lib/module/web/utils/blockUtils.js.map +1 -0
- package/lib/module/web/utils/browserUtils.js +36 -0
- package/lib/module/web/utils/browserUtils.js.map +1 -0
- package/lib/module/web/utils/cursorUtils.js +150 -0
- package/lib/module/web/utils/cursorUtils.js.map +1 -0
- package/lib/module/web/utils/inputUtils.js +144 -0
- package/lib/module/web/utils/inputUtils.js.map +1 -0
- package/lib/module/web/utils/measureUtils.js +0 -0
- package/lib/module/web/utils/measureUtils.js.map +1 -0
- package/lib/module/web/utils/parserUtils.js +547 -0
- package/lib/module/web/utils/parserUtils.js.map +1 -0
- package/lib/module/web/utils/treeUtils.js +103 -0
- package/lib/module/web/utils/treeUtils.js.map +1 -0
- package/lib/module/web/utils/webStyleUtils.js +54 -0
- package/lib/module/web/utils/webStyleUtils.js.map +1 -0
- package/lib/typescript/commonjs/e2e/checks.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/checks.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/editing.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/editing.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/helpers.d.ts +23 -0
- package/lib/typescript/commonjs/e2e/helpers.d.ts.map +1 -0
- package/lib/typescript/commonjs/e2e/smoke.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/smoke.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +22 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +41 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts +7 -0
- package/lib/typescript/commonjs/src/NativeMarcusModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts +10 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +5 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts +8 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts +8 -0
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/rangeUtils.d.ts +6 -0
- package/lib/typescript/commonjs/src/rangeUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts +8 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/InputHistory.d.ts +24 -0
- package/lib/typescript/commonjs/src/web/InputHistory.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +41 -0
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +33 -0
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts +7 -0
- package/lib/typescript/commonjs/src/web/utils/browserUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/utils/cursorUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/web/utils/inputUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts +22 -0
- package/lib/typescript/commonjs/src/web/utils/measureUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +44 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +25 -0
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +7 -0
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -0
- package/lib/typescript/module/e2e/checks.test.d.ts +2 -0
- package/lib/typescript/module/e2e/checks.test.d.ts.map +1 -0
- package/lib/typescript/module/e2e/editing.test.d.ts +2 -0
- package/lib/typescript/module/e2e/editing.test.d.ts.map +1 -0
- package/lib/typescript/module/e2e/helpers.d.ts +23 -0
- package/lib/typescript/module/e2e/helpers.d.ts.map +1 -0
- package/lib/typescript/module/e2e/smoke.test.d.ts +2 -0
- package/lib/typescript/module/e2e/smoke.test.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +63 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts +22 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +41 -0
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -0
- package/lib/typescript/module/src/NativeMarcusModule.d.ts +7 -0
- package/lib/typescript/module/src/NativeMarcusModule.d.ts.map +1 -0
- package/lib/typescript/module/src/commonTypes.d.ts +10 -0
- package/lib/typescript/module/src/commonTypes.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +5 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/index.d.ts +8 -0
- package/lib/typescript/module/src/parser/index.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts +8 -0
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -0
- package/lib/typescript/module/src/rangeUtils.d.ts +6 -0
- package/lib/typescript/module/src/rangeUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/styleUtils.d.ts +8 -0
- package/lib/typescript/module/src/styleUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/InputHistory.d.ts +24 -0
- package/lib/typescript/module/src/web/InputHistory.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts +41 -0
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts +33 -0
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/browserUtils.d.ts +7 -0
- package/lib/typescript/module/src/web/utils/browserUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/cursorUtils.d.ts +12 -0
- package/lib/typescript/module/src/web/utils/cursorUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/inputUtils.d.ts +12 -0
- package/lib/typescript/module/src/web/utils/inputUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/measureUtils.d.ts +22 -0
- package/lib/typescript/module/src/web/utils/measureUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts +44 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts +25 -0
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +7 -0
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -0
- package/package.json +167 -0
- package/react-native.config.js +10 -0
- package/src/MarcusTextInputDecoratorViewNativeComponent.ts +77 -0
- package/src/MarkdownTextInput.tsx +139 -0
- package/src/MarkdownTextInput.web.tsx +958 -0
- package/src/NativeMarcusModule.ts +8 -0
- package/src/commonTypes.ts +30 -0
- package/src/global.d.ts +1 -0
- package/src/index.tsx +4 -0
- package/src/parser/index.ts +556 -0
- package/src/parser/micromark-extension-mentions.ts +82 -0
- package/src/rangeUtils.ts +68 -0
- package/src/react-native-web.d.ts +1 -0
- package/src/styleUtils.ts +100 -0
- package/src/web/InputHistory.ts +137 -0
- package/src/web/MarkdownTextInput.css +72 -0
- package/src/web/utils/blockLayout.ts +163 -0
- package/src/web/utils/blockUtils.ts +245 -0
- package/src/web/utils/browserUtils.ts +41 -0
- package/src/web/utils/cursorUtils.ts +204 -0
- package/src/web/utils/inputUtils.ts +206 -0
- package/src/web/utils/measureUtils.ts +0 -0
- package/src/web/utils/parserUtils.ts +813 -0
- package/src/web/utils/treeUtils.ts +149 -0
- 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
|
+
}
|