react-native-marcus 0.1.1 → 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.
- package/README.md +220 -63
- package/RNMarcus.podspec +6 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusPackage.kt +2 -1
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorView.kt +168 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManager.kt +38 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextDecoratorViewManagerSpec.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarcusTextInputDecoratorView.kt +23 -1
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPainter.kt +147 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownBackgroundPass.kt +19 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownCopy.kt +87 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownFormatter.kt +652 -113
- package/android/src/main/java/app/getbullet/marcus/MarkdownRanges.kt +47 -0
- package/android/src/main/java/app/getbullet/marcus/MarkdownStyle.kt +140 -61
- package/android/src/main/java/app/getbullet/marcus/MarkdownUtils.kt +37 -7
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownAbsoluteLineHeightSpan.kt +48 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundSpan.kt +102 -48
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBlockIndentSpan.kt +22 -4
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBulletSpan.kt +78 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpan.kt +177 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontStyleSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownFontWeightSpan.kt +34 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownGapSpan.kt +24 -11
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownLetterSpacingSpan.kt +32 -0
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownTextShadowSpan.kt +32 -0
- package/android/src/main/new_arch/CMakeLists.txt +17 -0
- package/android/src/main/new_arch/RNMarcusSpec.h +1 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.cpp +235 -0
- package/android/src/main/new_arch/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorShadowNode.h +62 -0
- package/android/src/reactNativeVersionPatch/CustomMountingManager/81/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/reactNativeVersionPatch/CustomMountingManager/latest/app/getbullet/marcus/CustomFabricUIManager.java +22 -3
- package/android/src/test/java/app/getbullet/marcus/MarkdownCopyTest.kt +69 -0
- package/android/src/test/java/app/getbullet/marcus/MarkdownFormatterTest.kt +170 -25
- package/android/src/test/java/app/getbullet/marcus/RenderModel.kt +22 -5
- package/android/src/test/java/app/getbullet/marcus/spans/MarkdownCodeBlockSpanTest.kt +91 -0
- package/android/src/test/resources/render-model.txt +221 -16
- package/apple/MarcusSwizzle.h +25 -0
- package/apple/MarcusTextDecoratorComponentView.h +22 -0
- package/apple/MarcusTextDecoratorComponentView.mm +72 -0
- package/apple/MarcusTextDecoratorShadowNode.h +62 -0
- package/apple/MarcusTextDecoratorShadowNode.mm +192 -0
- package/apple/MarcusTextDecoratorViewManager.h +4 -0
- package/apple/MarcusTextDecoratorViewManager.mm +11 -0
- package/apple/MarcusTextInputDecoratorComponentView.mm +1 -1
- package/apple/MarcusTextInputDecoratorShadowNode.mm +1 -1
- package/apple/MarcusTextLayoutManager.h +40 -0
- package/apple/MarcusTextLayoutManager.mm +173 -0
- package/apple/MarkdownAttributes.h +23 -2
- package/apple/MarkdownAttributes.m +6 -0
- package/apple/MarkdownCopy.swift +63 -0
- package/apple/MarkdownDecorator.swift +2 -2
- package/apple/MarkdownFormatter+React.swift +23 -0
- package/apple/MarkdownFormatter.swift +869 -148
- package/apple/MarkdownParagraphLayoutManager.swift +455 -0
- package/apple/MarkdownSwiftInterop.h +0 -1
- package/apple/MarkdownTextBackground.swift +59 -1
- package/apple/MarkdownTextFieldObserver.swift +2 -2
- package/apple/MarkdownTextLayoutFragment.swift +159 -33
- package/apple/MarkdownTextLayoutManagerDelegate.swift +67 -3
- package/apple/MarkdownTextStorageDelegate.swift +2 -2
- package/apple/MarkdownTextViewObserver.swift +2 -2
- package/apple/MarkdownUtils.swift +38 -0
- package/apple/MarkdownWritingDirection.swift +132 -0
- package/apple/RCTMarcusStyle+Codegen.h +115 -9
- package/apple/RCTMarcusStyle.h +128 -31
- package/apple/RCTMarcusStyle.m +48 -0
- package/apple/RCTParagraphComponentView+Marcus.h +17 -0
- package/apple/RCTParagraphComponentView+Marcus.mm +38 -0
- package/apple/RCTTextInputComponentView+Marcus.mm +1 -25
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorState.h +37 -0
- package/cpp/react/renderer/components/RNMarcusSpec/MarcusTextDecoratorViewComponentDescriptor.h +17 -0
- package/lib/commonjs/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/commonjs/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/commonjs/MarkdownText.js +330 -0
- package/lib/commonjs/MarkdownText.js.map +1 -0
- package/lib/commonjs/MarkdownText.web.js +529 -0
- package/lib/commonjs/MarkdownText.web.js.map +1 -0
- package/lib/commonjs/MarkdownTextInput.js +22 -27
- package/lib/commonjs/MarkdownTextInput.js.map +1 -1
- package/lib/commonjs/MarkdownTextInput.web.js +12 -7
- package/lib/commonjs/MarkdownTextInput.web.js.map +1 -1
- package/lib/commonjs/atomUtils.js +112 -0
- package/lib/commonjs/atomUtils.js.map +1 -0
- package/lib/commonjs/childrenUtils.js +36 -0
- package/lib/commonjs/childrenUtils.js.map +1 -0
- package/lib/commonjs/index.js +8 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/math/environment.js +69 -0
- package/lib/commonjs/math/environment.js.map +1 -0
- package/lib/commonjs/math/index.js +61 -0
- package/lib/commonjs/math/index.js.map +1 -0
- package/lib/commonjs/math/mathjax.js +548 -0
- package/lib/commonjs/math/mathjax.js.map +1 -0
- package/lib/commonjs/metro.js +172 -0
- package/lib/commonjs/metro.js.map +1 -0
- package/lib/commonjs/parser/index.d.ts +3 -0
- package/lib/commonjs/parser/index.js +450 -42
- package/lib/commonjs/parser/index.js.map +4 -4
- package/lib/commonjs/stripUtils.js +743 -0
- package/lib/commonjs/stripUtils.js.map +1 -0
- package/lib/commonjs/styleUtils.js +194 -23
- package/lib/commonjs/styleUtils.js.map +1 -1
- package/lib/commonjs/web/MarkdownElements.css +67 -0
- package/lib/commonjs/web/MarkdownTextInput.css +9 -7
- package/lib/commonjs/web/utils/blockLayout.js +95 -7
- package/lib/commonjs/web/utils/blockLayout.js.map +1 -1
- package/lib/commonjs/web/utils/blockUtils.js +327 -54
- package/lib/commonjs/web/utils/blockUtils.js.map +1 -1
- package/lib/commonjs/web/utils/elementUtils.js +80 -0
- package/lib/commonjs/web/utils/elementUtils.js.map +1 -0
- package/lib/commonjs/web/utils/parserUtils.js +84 -28
- package/lib/commonjs/web/utils/parserUtils.js.map +1 -1
- package/lib/commonjs/web/utils/treeUtils.js +6 -0
- package/lib/commonjs/web/utils/treeUtils.js.map +1 -1
- package/lib/commonjs/web/utils/webStyleUtils.js +25 -5
- package/lib/commonjs/web/utils/webStyleUtils.js.map +1 -1
- package/lib/module/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/lib/module/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/lib/module/MarkdownText.js +325 -0
- package/lib/module/MarkdownText.js.map +1 -0
- package/lib/module/MarkdownText.web.js +524 -0
- package/lib/module/MarkdownText.web.js.map +1 -0
- package/lib/module/MarkdownTextInput.js +24 -29
- package/lib/module/MarkdownTextInput.js.map +1 -1
- package/lib/module/MarkdownTextInput.web.js +12 -7
- package/lib/module/MarkdownTextInput.web.js.map +1 -1
- package/lib/module/atomUtils.js +106 -0
- package/lib/module/atomUtils.js.map +1 -0
- package/lib/module/childrenUtils.js +33 -0
- package/lib/module/childrenUtils.js.map +1 -0
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/math/environment.js +67 -0
- package/lib/module/math/environment.js.map +1 -0
- package/lib/module/math/index.js +56 -0
- package/lib/module/math/index.js.map +1 -0
- package/lib/module/math/mathjax.js +541 -0
- package/lib/module/math/mathjax.js.map +1 -0
- package/lib/module/metro.js +169 -0
- package/lib/module/metro.js.map +1 -0
- package/lib/module/parser/index.d.ts +3 -0
- package/lib/module/parser/index.js +450 -42
- package/lib/module/parser/index.js.map +4 -4
- package/lib/module/stripUtils.js +739 -0
- package/lib/module/stripUtils.js.map +1 -0
- package/lib/module/styleUtils.js +196 -25
- package/lib/module/styleUtils.js.map +1 -1
- package/lib/module/web/MarkdownElements.css +67 -0
- package/lib/module/web/MarkdownTextInput.css +9 -7
- package/lib/module/web/utils/blockLayout.js +94 -8
- package/lib/module/web/utils/blockLayout.js.map +1 -1
- package/lib/module/web/utils/blockUtils.js +328 -56
- package/lib/module/web/utils/blockUtils.js.map +1 -1
- package/lib/module/web/utils/elementUtils.js +75 -0
- package/lib/module/web/utils/elementUtils.js.map +1 -0
- package/lib/module/web/utils/parserUtils.js +86 -30
- package/lib/module/web/utils/parserUtils.js.map +1 -1
- package/lib/module/web/utils/treeUtils.js +6 -0
- package/lib/module/web/utils/treeUtils.js.map +1 -1
- package/lib/module/web/utils/webStyleUtils.js +25 -5
- package/lib/module/web/utils/webStyleUtils.js.map +1 -1
- package/lib/typescript/commonjs/e2e/links.test.d.ts +2 -0
- package/lib/typescript/commonjs/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/commonjs/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/commonjs/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/commonjs/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/commonjs/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/commonjs/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/atomUtils.d.ts +58 -0
- package/lib/typescript/commonjs/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/commonjs/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/commonTypes.d.ts +39 -3
- package/lib/typescript/commonjs/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/math/environment.d.ts +7 -0
- package/lib/typescript/commonjs/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/index.d.ts +64 -0
- package/lib/typescript/commonjs/src/math/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/commonjs/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/metro.d.ts +59 -0
- package/lib/typescript/commonjs/src/metro.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/parser/index.d.ts +3 -3
- package/lib/typescript/commonjs/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/commonjs/src/stripUtils.d.ts +108 -0
- package/lib/typescript/commonjs/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/styleUtils.d.ts +62 -4
- package/lib/typescript/commonjs/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/commonjs/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/commonjs/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/commonjs/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/commonjs/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/commonjs/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/commonjs/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/lib/typescript/module/e2e/links.test.d.ts +2 -0
- package/lib/typescript/module/e2e/links.test.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts +93 -0
- package/lib/typescript/module/src/MarcusTextDecoratorViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts +64 -51
- package/lib/typescript/module/src/MarcusTextInputDecoratorViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownText.d.ts +127 -0
- package/lib/typescript/module/src/MarkdownText.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts +126 -0
- package/lib/typescript/module/src/MarkdownText.web.d.ts.map +1 -0
- package/lib/typescript/module/src/MarkdownTextInput.d.ts +23 -1
- package/lib/typescript/module/src/MarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts +26 -4
- package/lib/typescript/module/src/MarkdownTextInput.web.d.ts.map +1 -1
- package/lib/typescript/module/src/atomUtils.d.ts +58 -0
- package/lib/typescript/module/src/atomUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/childrenUtils.d.ts +12 -0
- package/lib/typescript/module/src/childrenUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/commonTypes.d.ts +39 -3
- package/lib/typescript/module/src/commonTypes.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/math/environment.d.ts +7 -0
- package/lib/typescript/module/src/math/environment.d.ts.map +1 -0
- package/lib/typescript/module/src/math/index.d.ts +64 -0
- package/lib/typescript/module/src/math/index.d.ts.map +1 -0
- package/lib/typescript/module/src/math/mathjax.d.ts +63 -0
- package/lib/typescript/module/src/math/mathjax.d.ts.map +1 -0
- package/lib/typescript/module/src/metro.d.ts +59 -0
- package/lib/typescript/module/src/metro.d.ts.map +1 -0
- package/lib/typescript/module/src/parser/index.d.ts +3 -3
- package/lib/typescript/module/src/parser/index.d.ts.map +1 -1
- package/lib/typescript/module/src/parser/micromark-extension-mentions.d.ts.map +1 -1
- package/lib/typescript/module/src/rangeUtils.d.ts +1 -1
- package/lib/typescript/module/src/stripUtils.d.ts +108 -0
- package/lib/typescript/module/src/stripUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/styleUtils.d.ts +62 -4
- package/lib/typescript/module/src/styleUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts +32 -4
- package/lib/typescript/module/src/web/utils/blockLayout.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts +20 -8
- package/lib/typescript/module/src/web/utils/blockUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts +37 -0
- package/lib/typescript/module/src/web/utils/elementUtils.d.ts.map +1 -0
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts +5 -5
- package/lib/typescript/module/src/web/utils/parserUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts +6 -1
- package/lib/typescript/module/src/web/utils/treeUtils.d.ts.map +1 -1
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts +2 -2
- package/lib/typescript/module/src/web/utils/webStyleUtils.d.ts.map +1 -1
- package/package.json +29 -2
- package/react-native.config.js +8 -1
- package/src/MarcusTextDecoratorViewNativeComponent.ts +199 -0
- package/src/MarcusTextInputDecoratorViewNativeComponent.ts +145 -58
- package/src/MarkdownText.tsx +472 -0
- package/src/MarkdownText.web.tsx +668 -0
- package/src/MarkdownTextInput.tsx +42 -38
- package/src/MarkdownTextInput.web.tsx +36 -13
- package/src/atomUtils.ts +112 -0
- package/src/childrenUtils.ts +39 -0
- package/src/commonTypes.ts +69 -9
- package/src/index.tsx +2 -1
- package/src/math/environment.ts +68 -0
- package/src/math/index.ts +78 -0
- package/src/math/mathjax.ts +604 -0
- package/src/metro.ts +238 -0
- package/src/parser/index.ts +175 -10
- package/src/parser/micromark-extension-mentions.ts +104 -11
- package/src/stripUtils.ts +919 -0
- package/src/styleUtils.ts +290 -26
- package/src/web/MarkdownElements.css +67 -0
- package/src/web/MarkdownTextInput.css +9 -7
- package/src/web/utils/blockLayout.ts +124 -14
- package/src/web/utils/blockUtils.ts +365 -59
- package/src/web/utils/elementUtils.ts +87 -0
- package/src/web/utils/parserUtils.ts +119 -31
- package/src/web/utils/treeUtils.ts +6 -1
- package/src/web/utils/webStyleUtils.ts +32 -8
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBackgroundColorSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownBoldSpan.kt +0 -6
- package/android/src/main/java/app/getbullet/marcus/spans/MarkdownItalicSpan.kt +0 -6
- package/apple/RCTMarcusStyle+Codegen.mm +0 -64
- package/apple/RCTMarcusUtils.h +0 -26
- package/apple/RCTMarcusUtils.mm +0 -26
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#include "MarcusTextDecoratorShadowNode.h"
|
|
2
|
+
|
|
3
|
+
#include <fbjni/fbjni.h>
|
|
4
|
+
#include <react/fabric/JFabricUIManager.h>
|
|
5
|
+
#include <react/jni/ReadableNativeArray.h>
|
|
6
|
+
#include <react/jni/ReadableNativeMap.h>
|
|
7
|
+
#if REACT_NATIVE_MINOR_VERSION < 80
|
|
8
|
+
#include <react/jni/SafeReleaseJniRef.h>
|
|
9
|
+
#endif // REACT_NATIVE_MINOR_VERSION < 80
|
|
10
|
+
#include <react/renderer/components/text/ParagraphShadowNode.h>
|
|
11
|
+
#include <react/renderer/components/view/conversions.h>
|
|
12
|
+
#include <react/renderer/core/ComponentDescriptor.h>
|
|
13
|
+
|
|
14
|
+
namespace facebook {
|
|
15
|
+
namespace react {
|
|
16
|
+
|
|
17
|
+
extern const char MarcusTextDecoratorViewComponentName[] =
|
|
18
|
+
"MarcusTextDecoratorView";
|
|
19
|
+
|
|
20
|
+
MarcusTextDecoratorShadowNode::MarcusTextDecoratorShadowNode(
|
|
21
|
+
ShadowNodeFragment const &fragment, ShadowNodeFamily::Shared const &family, ShadowNodeTraits traits
|
|
22
|
+
)
|
|
23
|
+
: ConcreteViewShadowNode(fragment, family, traits) {
|
|
24
|
+
initialize();
|
|
25
|
+
createCustomContextContainer();
|
|
26
|
+
makeChildNodeMutable();
|
|
27
|
+
|
|
28
|
+
if (fragment.children) {
|
|
29
|
+
overwriteTextLayoutManager();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
MarcusTextDecoratorShadowNode::MarcusTextDecoratorShadowNode(
|
|
34
|
+
ShadowNode const &sourceShadowNode, ShadowNodeFragment const &fragment
|
|
35
|
+
)
|
|
36
|
+
: ConcreteViewShadowNode(sourceShadowNode, fragment) {
|
|
37
|
+
initialize();
|
|
38
|
+
|
|
39
|
+
const auto &sourceDecorator =
|
|
40
|
+
static_cast<const MarcusTextDecoratorShadowNode &>(sourceShadowNode);
|
|
41
|
+
|
|
42
|
+
customContextContainer_ = sourceDecorator.customContextContainer_;
|
|
43
|
+
previousMarkdownStyle_ = sourceDecorator.previousMarkdownStyle_;
|
|
44
|
+
previousRanges_ = sourceDecorator.previousRanges_;
|
|
45
|
+
|
|
46
|
+
updateCustomContextContainerIfNeeded();
|
|
47
|
+
makeChildNodeMutable();
|
|
48
|
+
|
|
49
|
+
if (fragment.children) {
|
|
50
|
+
overwriteTextLayoutManager();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void
|
|
55
|
+
MarcusTextDecoratorShadowNode::initialize() {
|
|
56
|
+
// Setting display: contents style results in ForceFlattenView trait being set
|
|
57
|
+
// on the shadow node. This trait causes the node not to have a host view. By
|
|
58
|
+
// removing the trait, it's possible to force RN to create a host view, layout
|
|
59
|
+
// of which can then be customized.
|
|
60
|
+
ShadowNode::traits_.unset(ShadowNodeTraits::ForceFlattenView);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void
|
|
64
|
+
MarcusTextDecoratorShadowNode::makeChildNodeMutable() {
|
|
65
|
+
// When the decorator is cloned and has a child node, the child node should be
|
|
66
|
+
// cloned as well to ensure it is mutable. Cloning it also runs the paragraph's
|
|
67
|
+
// own component descriptor, which resets the layout manager to the shared one,
|
|
68
|
+
// so overwriteTextLayoutManager() always follows this rather than preceding it.
|
|
69
|
+
const auto &children = getChildren();
|
|
70
|
+
if (!children.empty()) {
|
|
71
|
+
react_native_assert(
|
|
72
|
+
children.size() == 1 &&
|
|
73
|
+
"MarcusTextDecoratorView received more than one child"
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const auto clonedChild = children[0]->clone({});
|
|
77
|
+
replaceChild(*children[0], clonedChild);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void
|
|
82
|
+
MarcusTextDecoratorShadowNode::createCustomContextContainer() {
|
|
83
|
+
static const auto customFabricUIManagerClass =
|
|
84
|
+
jni::findClassStatic("app/getbullet/marcus/CustomFabricUIManager");
|
|
85
|
+
static const auto createMethod =
|
|
86
|
+
customFabricUIManagerClass->getStaticMethod<JFabricUIManager::javaobject(
|
|
87
|
+
JFabricUIManager::javaobject, ReadableMap::javaobject, ReadableArray::javaobject
|
|
88
|
+
)>(
|
|
89
|
+
"createForText"
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const auto &rawProps = this->getProps()->rawProps;
|
|
93
|
+
const auto &markdownStyleIt = rawProps.find("markdownStyle");
|
|
94
|
+
const auto &markdownStyle = markdownStyleIt != rawProps.items().end()
|
|
95
|
+
? markdownStyleIt->second
|
|
96
|
+
: previousMarkdownStyle_;
|
|
97
|
+
const auto &rangesIt = rawProps.find("ranges");
|
|
98
|
+
const auto &ranges =
|
|
99
|
+
rangesIt != rawProps.items().end() ? rangesIt->second : previousRanges_;
|
|
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
|
+
// An absent or malformed prop still has to produce an array: the Java side
|
|
108
|
+
// takes one, and an empty one simply formats nothing.
|
|
109
|
+
const auto rangesRNA = ReadableNativeArray::newObjectCxxArgs(
|
|
110
|
+
ranges.isArray() ? ranges : folly::dynamic::array()
|
|
111
|
+
);
|
|
112
|
+
const auto rangesRA = jni::make_local(
|
|
113
|
+
reinterpret_cast<ReadableArray::javaobject>(rangesRNA.get())
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const auto &fabricUIManager =
|
|
117
|
+
this->getContextContainer()->at<JFabricUIManager::javaobject>(
|
|
118
|
+
"FabricUIManager"
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const auto customFabricUIManager = SafeReleaseJniRef(
|
|
122
|
+
jni::make_global(createMethod(customFabricUIManagerClass, fabricUIManager, decoratorPropsRM.get(), rangesRA.get()))
|
|
123
|
+
);
|
|
124
|
+
const auto contextContainer = std::make_shared<ContextContainer const>();
|
|
125
|
+
contextContainer->insert("FabricUIManager", customFabricUIManager);
|
|
126
|
+
|
|
127
|
+
customContextContainer_ = contextContainer;
|
|
128
|
+
previousMarkdownStyle_ = markdownStyle;
|
|
129
|
+
previousRanges_ = ranges;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
void
|
|
133
|
+
MarcusTextDecoratorShadowNode::updateCustomContextContainerIfNeeded() {
|
|
134
|
+
const auto &rawProps = this->getProps()->rawProps;
|
|
135
|
+
const auto &markdownStyleIt = rawProps.find("markdownStyle");
|
|
136
|
+
if (markdownStyleIt != rawProps.items().end() &&
|
|
137
|
+
markdownStyleIt->second != previousMarkdownStyle_) {
|
|
138
|
+
createCustomContextContainer();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const auto &rangesIt = rawProps.find("ranges");
|
|
142
|
+
if (rangesIt != rawProps.items().end() &&
|
|
143
|
+
rangesIt->second != previousRanges_) {
|
|
144
|
+
createCustomContextContainer();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void
|
|
149
|
+
MarcusTextDecoratorShadowNode::overwriteTextLayoutManager() {
|
|
150
|
+
const auto &children = getChildren();
|
|
151
|
+
if (children.empty()) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
react_native_assert(
|
|
155
|
+
children.size() == 1 &&
|
|
156
|
+
"MarcusTextDecoratorView received more than one child"
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const auto child =
|
|
160
|
+
std::dynamic_pointer_cast<const ParagraphShadowNode>(children[0]);
|
|
161
|
+
|
|
162
|
+
react_native_assert(
|
|
163
|
+
child != nullptr &&
|
|
164
|
+
"MarcusTextDecoratorView received child other than a Text"
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (child == nullptr) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
child->ensureUnsealed();
|
|
172
|
+
|
|
173
|
+
const auto mutableChild =
|
|
174
|
+
std::const_pointer_cast<ParagraphShadowNode>(child);
|
|
175
|
+
mutableChild->setTextLayoutManager(
|
|
176
|
+
std::make_shared<TextLayoutManager>(customContextContainer_)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
void
|
|
181
|
+
MarcusTextDecoratorShadowNode::appendChild(
|
|
182
|
+
const std::shared_ptr<const ShadowNode> &child
|
|
183
|
+
) {
|
|
184
|
+
YogaLayoutableShadowNode::appendChild(child);
|
|
185
|
+
|
|
186
|
+
overwriteTextLayoutManager();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
void
|
|
190
|
+
MarcusTextDecoratorShadowNode::replaceChild(
|
|
191
|
+
const ShadowNode &oldChild,
|
|
192
|
+
const std::shared_ptr<const ShadowNode> &newChild,
|
|
193
|
+
size_t suggestedIndex
|
|
194
|
+
) {
|
|
195
|
+
YogaLayoutableShadowNode::replaceChild(oldChild, newChild, suggestedIndex);
|
|
196
|
+
|
|
197
|
+
overwriteTextLayoutManager();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
void
|
|
201
|
+
MarcusTextDecoratorShadowNode::layout(LayoutContext layoutContext) {
|
|
202
|
+
YogaLayoutableShadowNode::layout(layoutContext);
|
|
203
|
+
|
|
204
|
+
const auto &children = getChildren();
|
|
205
|
+
react_native_assert(
|
|
206
|
+
children.size() == 1 &&
|
|
207
|
+
"MarcusTextDecoratorView didn't receive exactly one child"
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (children.size() != 1) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
auto child =
|
|
215
|
+
std::static_pointer_cast<const YogaLayoutableShadowNode>(children[0]);
|
|
216
|
+
child->ensureUnsealed();
|
|
217
|
+
auto mutableChild = std::const_pointer_cast<YogaLayoutableShadowNode>(child);
|
|
218
|
+
|
|
219
|
+
// Since nodes with display: contents are skipped during layout, they have
|
|
220
|
+
// zero-layout. To properly display the view, assign the layout metrics from
|
|
221
|
+
// the child (the paragraph, which was calculated by Yoga) to the decorator
|
|
222
|
+
// view.
|
|
223
|
+
auto childMetrics = child->getLayoutMetrics(); // makes a copy
|
|
224
|
+
setLayoutMetrics(childMetrics);
|
|
225
|
+
|
|
226
|
+
// Then, it's also needed to update the metrics on the child as the position
|
|
227
|
+
// is relative to the parent, which was just moved above. By zeroing the
|
|
228
|
+
// origin, the child is effectively moved to the same position it was before
|
|
229
|
+
// the manipulation here.
|
|
230
|
+
childMetrics.frame.origin = Point{};
|
|
231
|
+
mutableChild->setLayoutMetrics(childMetrics);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
} // namespace react
|
|
235
|
+
} // namespace facebook
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <react/renderer/components/RNMarcusSpec/EventEmitters.h>
|
|
4
|
+
#include <react/renderer/components/RNMarcusSpec/MarcusTextDecoratorState.h>
|
|
5
|
+
#include <react/renderer/components/RNMarcusSpec/Props.h>
|
|
6
|
+
|
|
7
|
+
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
|
8
|
+
#include <react/renderer/core/LayoutContext.h>
|
|
9
|
+
|
|
10
|
+
namespace facebook {
|
|
11
|
+
namespace react {
|
|
12
|
+
|
|
13
|
+
JSI_EXPORT extern const char MarcusTextDecoratorViewComponentName[];
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Wraps a `Text` and gives the paragraph underneath it a text layout manager
|
|
17
|
+
* that formats before it measures.
|
|
18
|
+
*
|
|
19
|
+
* The measure half of the story only. Android builds a second spannable on the
|
|
20
|
+
* UI thread when the text is mounted, and the callback React Native offers
|
|
21
|
+
* there belongs to the view manager rather than to one `Text`, so that half is
|
|
22
|
+
* `MarcusTextDecoratorView`'s job.
|
|
23
|
+
*/
|
|
24
|
+
class JSI_EXPORT MarcusTextDecoratorShadowNode final
|
|
25
|
+
: public ConcreteViewShadowNode<MarcusTextDecoratorViewComponentName, MarcusTextDecoratorViewProps, MarcusTextDecoratorViewEventEmitter, MarcusTextDecoratorState> {
|
|
26
|
+
public:
|
|
27
|
+
MarcusTextDecoratorShadowNode(ShadowNodeFragment const &fragment, ShadowNodeFamily::Shared const &family, ShadowNodeTraits traits);
|
|
28
|
+
|
|
29
|
+
MarcusTextDecoratorShadowNode(ShadowNode const &sourceShadowNode, ShadowNodeFragment const &fragment);
|
|
30
|
+
|
|
31
|
+
void
|
|
32
|
+
appendChild(const std::shared_ptr<const ShadowNode> &child) override;
|
|
33
|
+
|
|
34
|
+
void
|
|
35
|
+
replaceChild(const ShadowNode &oldChild, const std::shared_ptr<const ShadowNode> &newChild, size_t suggestedIndex = SIZE_MAX) override;
|
|
36
|
+
|
|
37
|
+
void
|
|
38
|
+
layout(LayoutContext layoutContext) override;
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
std::shared_ptr<const ContextContainer> customContextContainer_;
|
|
42
|
+
folly::dynamic previousMarkdownStyle_;
|
|
43
|
+
folly::dynamic previousRanges_;
|
|
44
|
+
|
|
45
|
+
void
|
|
46
|
+
initialize();
|
|
47
|
+
|
|
48
|
+
void
|
|
49
|
+
overwriteTextLayoutManager();
|
|
50
|
+
|
|
51
|
+
void
|
|
52
|
+
createCustomContextContainer();
|
|
53
|
+
|
|
54
|
+
void
|
|
55
|
+
updateCustomContextContainerIfNeeded();
|
|
56
|
+
|
|
57
|
+
void
|
|
58
|
+
makeChildNodeMutable();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
} // namespace react
|
|
62
|
+
} // namespace facebook
|
|
@@ -25,6 +25,7 @@ import com.facebook.infer.annotation.Assertions;
|
|
|
25
25
|
import com.facebook.jni.annotations.DoNotStrip;
|
|
26
26
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
27
27
|
import com.facebook.react.bridge.ReactContext;
|
|
28
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
28
29
|
import com.facebook.react.bridge.ReadableMap;
|
|
29
30
|
import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
|
|
30
31
|
import com.facebook.react.fabric.FabricUIManager;
|
|
@@ -49,16 +50,20 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
49
50
|
BatchEventDispatchedListener batchEventDispatchedListener,
|
|
50
51
|
MountingManager mountingManager,
|
|
51
52
|
ReadableMap markdownProps,
|
|
52
|
-
int parserId
|
|
53
|
+
int parserId,
|
|
54
|
+
@Nullable ReadableArray ranges
|
|
53
55
|
) {
|
|
54
56
|
super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
|
|
55
57
|
|
|
56
58
|
this.mReactApplicationContext = reactContext;
|
|
57
59
|
this.mMountingManager = mountingManager;
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
// A `Text` is the one caller that arrives with ranges, and the one whose list
|
|
62
|
+
// markers are rendered rather than shown.
|
|
63
|
+
this.mMarkdownUtils = new MarkdownUtils(reactContext, null, null, ranges != null);
|
|
60
64
|
this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
|
|
61
65
|
this.mMarkdownUtils.setParserId(parserId);
|
|
66
|
+
this.mMarkdownUtils.setRanges(ranges == null ? null : MarkdownRanges.read(ranges));
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
@Override
|
|
@@ -100,7 +105,20 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
100
105
|
attachmentsPositions);
|
|
101
106
|
}
|
|
102
107
|
|
|
108
|
+
|
|
109
|
+
// Two ways in. A `TextInput` supplies a parser id and the text is parsed here, on the background
|
|
110
|
+
// thread that measures it. A `Text` supplies finished ranges: its content only changes by a
|
|
111
|
+
// re-render, so JavaScript already knows the string and has already stripped the syntax out of
|
|
112
|
+
// it. Everything past that point is the same formatting.
|
|
103
113
|
public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
|
|
114
|
+
return create(source, markdownProps, parserId, null);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public static FabricUIManager createForText(FabricUIManager source, ReadableMap markdownProps, ReadableArray ranges) {
|
|
118
|
+
return create(source, markdownProps, 0, ranges);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId, @Nullable ReadableArray ranges) {
|
|
104
122
|
try {
|
|
105
123
|
MountingManager sourceMountingManager = readPrivateField(source, "mMountingManager");
|
|
106
124
|
ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
|
|
@@ -113,7 +131,8 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
113
131
|
batchEventDispatchedListener,
|
|
114
132
|
sourceMountingManager,
|
|
115
133
|
markdownProps,
|
|
116
|
-
parserId
|
|
134
|
+
parserId,
|
|
135
|
+
ranges
|
|
117
136
|
);
|
|
118
137
|
|
|
119
138
|
return customFabricUIManager;
|
|
@@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
|
|
|
23
23
|
|
|
24
24
|
import com.facebook.jni.annotations.DoNotStrip;
|
|
25
25
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
26
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
26
27
|
import com.facebook.react.bridge.ReadableMap;
|
|
27
28
|
import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
|
|
28
29
|
import com.facebook.react.fabric.FabricUIManager;
|
|
@@ -43,15 +44,19 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
43
44
|
ViewManagerRegistry viewManagerRegistry,
|
|
44
45
|
BatchEventDispatchedListener batchEventDispatchedListener,
|
|
45
46
|
ReadableMap markdownProps,
|
|
46
|
-
int parserId
|
|
47
|
+
int parserId,
|
|
48
|
+
@Nullable ReadableArray ranges
|
|
47
49
|
) {
|
|
48
50
|
super(reactContext, viewManagerRegistry, batchEventDispatchedListener);
|
|
49
51
|
|
|
50
52
|
this.mReactApplicationContext = reactContext;
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
// A `Text` is the one caller that arrives with ranges, and the one whose list
|
|
55
|
+
// markers are rendered rather than shown.
|
|
56
|
+
this.mMarkdownUtils = new MarkdownUtils(reactContext, null, null, ranges != null);
|
|
53
57
|
this.mMarkdownUtils.setMarkdownStyle(new MarkdownStyle(markdownProps, reactContext));
|
|
54
58
|
this.mMarkdownUtils.setParserId(parserId);
|
|
59
|
+
this.mMarkdownUtils.setRanges(ranges == null ? null : MarkdownRanges.read(ranges));
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
@Override
|
|
@@ -78,7 +83,20 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
78
83
|
attachmentsPositions);
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
|
|
87
|
+
// Two ways in. A `TextInput` supplies a parser id and the text is parsed here, on the background
|
|
88
|
+
// thread that measures it. A `Text` supplies finished ranges: its content only changes by a
|
|
89
|
+
// re-render, so JavaScript already knows the string and has already stripped the syntax out of
|
|
90
|
+
// it. Everything past that point is the same formatting.
|
|
81
91
|
public static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId) {
|
|
92
|
+
return create(source, markdownProps, parserId, null);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public static FabricUIManager createForText(FabricUIManager source, ReadableMap markdownProps, ReadableArray ranges) {
|
|
96
|
+
return create(source, markdownProps, 0, ranges);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private static FabricUIManager create(FabricUIManager source, ReadableMap markdownProps, int parserId, @Nullable ReadableArray ranges) {
|
|
82
100
|
try {
|
|
83
101
|
ReactApplicationContext reactContext = readPrivateField(source, "mReactApplicationContext");
|
|
84
102
|
ViewManagerRegistry viewManagerRegistry = readPrivateField(source, "mViewManagerRegistry");
|
|
@@ -89,7 +107,8 @@ public class CustomFabricUIManager extends FabricUIManager {
|
|
|
89
107
|
viewManagerRegistry,
|
|
90
108
|
batchEventDispatchedListener,
|
|
91
109
|
markdownProps,
|
|
92
|
-
parserId
|
|
110
|
+
parserId,
|
|
111
|
+
ranges
|
|
93
112
|
);
|
|
94
113
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
|
95
114
|
throw new RuntimeException("[Marcus] Cannot read data from FabricUIManager", e);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
import org.junit.Assert.assertEquals
|
|
4
|
+
import org.junit.Test
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* What a selection copies as.
|
|
8
|
+
*
|
|
9
|
+
* The placeholder is one object replacement character standing where a view is mounted in the
|
|
10
|
+
* text, in the same string and at the same offsets the `TextView` and the formatter both work in.
|
|
11
|
+
*/
|
|
12
|
+
class MarkdownCopyTest {
|
|
13
|
+
|
|
14
|
+
private val substitutions =
|
|
15
|
+
listOf(
|
|
16
|
+
MarkdownSubstitution(index = 5, text = "\$\$E = mc^2\$\$"),
|
|
17
|
+
MarkdownSubstitution(index = 16, text = "\$\$\\alpha\$\$"),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
private val text = "Where\uFFFCcomes from\uFFFCand more"
|
|
21
|
+
|
|
22
|
+
@Test
|
|
23
|
+
fun `writes every placeholder in the selection back out as its source`() {
|
|
24
|
+
assertEquals(
|
|
25
|
+
"Where\$\$E = mc^2\$\$comes from\$\$\\alpha\$\$and more",
|
|
26
|
+
MarkdownCopy.substitute(text, 0, text.length, substitutions),
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Test
|
|
31
|
+
fun `leaves a selection with no drawing in it exactly as it is`() {
|
|
32
|
+
assertEquals("comes from", MarkdownCopy.substitute(text, 6, 16, substitutions))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Test
|
|
36
|
+
fun `substitutes only the drawings the selection reaches`() {
|
|
37
|
+
assertEquals("\$\$E = mc^2\$\$comes from", MarkdownCopy.substitute(text, 5, 16, substitutions))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// An image copies as nothing, so its placeholder has to go rather than stay as a character that
|
|
41
|
+
// pastes as an empty box.
|
|
42
|
+
@Test
|
|
43
|
+
fun `drops a placeholder whose source is empty`() {
|
|
44
|
+
assertEquals(
|
|
45
|
+
"Wherecomes from",
|
|
46
|
+
MarkdownCopy.substitute(text, 0, 16, listOf(MarkdownSubstitution(index = 5, text = ""))),
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The props and the laid-out text are two sides of one commit, and a paragraph mounted between
|
|
51
|
+
// them is the one frame where they can disagree.
|
|
52
|
+
@Test
|
|
53
|
+
fun `ignores an offset that is not in the text`() {
|
|
54
|
+
assertEquals(
|
|
55
|
+
text,
|
|
56
|
+
MarkdownCopy.substitute(
|
|
57
|
+
text,
|
|
58
|
+
0,
|
|
59
|
+
text.length,
|
|
60
|
+
listOf(MarkdownSubstitution(index = 999, text = "\$\$x\$\$")),
|
|
61
|
+
),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@Test
|
|
66
|
+
fun `clamps a selection that runs past the end of the text`() {
|
|
67
|
+
assertEquals("and more", MarkdownCopy.substitute(text, 17, 9999, substitutions))
|
|
68
|
+
}
|
|
69
|
+
}
|