react-native-marcus 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -7,12 +7,23 @@ import com.facebook.react.bridge.ReactContext
|
|
|
7
7
|
import com.facebook.react.views.textinput.ReactEditText
|
|
8
8
|
import com.facebook.react.views.view.ReactViewGroup
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Formats the editable of the `TextInput` it wraps, and paints the backgrounds
|
|
12
|
+
* that would otherwise cover the caret.
|
|
13
|
+
*/
|
|
10
14
|
class MarcusTextInputDecoratorView(context: Context) : ReactViewGroup(context) {
|
|
11
15
|
|
|
12
16
|
private var markdownUtils: MarkdownUtils? = null
|
|
13
17
|
private var reactEditText: ReactEditText? = null
|
|
14
18
|
private var textWatcher: TextWatcher? = null
|
|
15
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Paints the markdown backgrounds before the text does, so that the caret --
|
|
22
|
+
* which Android draws before either -- is not covered by them.
|
|
23
|
+
*/
|
|
24
|
+
private val backgroundPass = MarkdownBackgroundPass()
|
|
25
|
+
private val backgroundPainter = MarkdownBackgroundPainter(backgroundPass)
|
|
26
|
+
|
|
16
27
|
var markdownStyle: MarkdownStyle? = null
|
|
17
28
|
set(value) {
|
|
18
29
|
field = value
|
|
@@ -32,12 +43,13 @@ class MarcusTextInputDecoratorView(context: Context) : ReactViewGroup(context) {
|
|
|
32
43
|
|
|
33
44
|
val child = getChildAt(0)
|
|
34
45
|
if (child is ReactEditText) {
|
|
35
|
-
val utils = MarkdownUtils(context as ReactContext, child.paint)
|
|
46
|
+
val utils = MarkdownUtils(context as ReactContext, child.paint, backgroundPass)
|
|
36
47
|
utils.markdownStyle = markdownStyle
|
|
37
48
|
utils.parserId = parserId
|
|
38
49
|
markdownUtils = utils
|
|
39
50
|
reactEditText = child
|
|
40
51
|
textWatcher = MarkdownTextWatcher(utils).also { child.addTextChangedListener(it) }
|
|
52
|
+
backgroundPainter.attachTo(child)
|
|
41
53
|
applyNewStyles()
|
|
42
54
|
}
|
|
43
55
|
}
|
|
@@ -46,6 +58,7 @@ class MarcusTextInputDecoratorView(context: Context) : ReactViewGroup(context) {
|
|
|
46
58
|
super.onDetachedFromWindow()
|
|
47
59
|
reactEditText?.let { editText ->
|
|
48
60
|
textWatcher?.let { editText.removeTextChangedListener(it) }
|
|
61
|
+
editText.setCompoundDrawables(null, null, null, null)
|
|
49
62
|
reactEditText = null
|
|
50
63
|
textWatcher = null
|
|
51
64
|
markdownUtils = null
|
|
@@ -55,6 +68,15 @@ class MarcusTextInputDecoratorView(context: Context) : ReactViewGroup(context) {
|
|
|
55
68
|
fun applyNewStyles() {
|
|
56
69
|
val editText = reactEditText ?: return
|
|
57
70
|
val utils = markdownUtils ?: return
|
|
71
|
+
|
|
72
|
+
// Puts the painter back if something else took the compound drawable slot it
|
|
73
|
+
// lives in. Only `inlineImageLeft` does, and it clears all four; checked here
|
|
74
|
+
// rather than per frame, where asking for it would cost a layout pass every
|
|
75
|
+
// time something wrapped our drawable rather than replacing it.
|
|
76
|
+
if (editText.compoundDrawables[3] == null) {
|
|
77
|
+
backgroundPainter.attachTo(editText)
|
|
78
|
+
}
|
|
79
|
+
|
|
58
80
|
val editable = editText.text
|
|
59
81
|
if (editable is SpannableStringBuilder) {
|
|
60
82
|
utils.applyMarkdownFormatting(editable)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
import android.graphics.Canvas
|
|
4
|
+
import android.graphics.ColorFilter
|
|
5
|
+
import android.graphics.PixelFormat
|
|
6
|
+
import android.graphics.Rect
|
|
7
|
+
import android.graphics.drawable.Drawable
|
|
8
|
+
import android.text.Layout
|
|
9
|
+
import android.text.Spanned
|
|
10
|
+
import android.text.style.LineBackgroundSpan
|
|
11
|
+
import android.widget.TextView
|
|
12
|
+
import app.getbullet.marcus.spans.MarkdownSpan
|
|
13
|
+
import java.lang.ref.WeakReference
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Paints the markdown backgrounds before the caret is drawn.
|
|
17
|
+
*
|
|
18
|
+
* A `TextView` draws its caret first and its text layout -- line backgrounds and
|
|
19
|
+
* all -- over the top, so anything opaque behind the text hides the caret.
|
|
20
|
+
* Android's own `BackgroundColorSpan` has the same effect; with a code block's
|
|
21
|
+
* box covering the width of every line it is impossible to miss.
|
|
22
|
+
*
|
|
23
|
+
* The one thing a `TextView` draws earlier, and that can be handed to a view we
|
|
24
|
+
* did not create, is a compound drawable: they are painted at the top of
|
|
25
|
+
* `onDraw`, before the cursor and before the text. So this is a drawable of no
|
|
26
|
+
* size, in the one slot React Native never uses, whose only job is to run the
|
|
27
|
+
* line background spans early. They are the same spans a `Text` paints through
|
|
28
|
+
* the layout -- one implementation, drawn at two different moments -- and
|
|
29
|
+
* [MarkdownBackgroundPass] is what keeps them from painting twice.
|
|
30
|
+
*
|
|
31
|
+
* The line walk mirrors `Layout.drawBackground`, which is not public until API
|
|
32
|
+
* 29 and would paint every line background rather than only ours.
|
|
33
|
+
*/
|
|
34
|
+
class MarkdownBackgroundPainter(private val pass: MarkdownBackgroundPass) : Drawable() {
|
|
35
|
+
|
|
36
|
+
private var textView: WeakReference<TextView>? = null
|
|
37
|
+
private val clip = Rect()
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Takes the bottom compound drawable slot: `inlineImageLeft` is the only one
|
|
41
|
+
* React Native sets, and it sets the left.
|
|
42
|
+
*/
|
|
43
|
+
fun attachTo(view: TextView) {
|
|
44
|
+
textView = WeakReference(view)
|
|
45
|
+
setBounds(0, 0, 0, 0)
|
|
46
|
+
view.compoundDrawablePadding = 0
|
|
47
|
+
view.setCompoundDrawables(null, null, null, this)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override fun draw(canvas: Canvas) {
|
|
51
|
+
val view = textView?.get() ?: return
|
|
52
|
+
val layout = view.layout ?: return
|
|
53
|
+
val text = layout.text as? Spanned ?: return
|
|
54
|
+
|
|
55
|
+
val spans = text.getSpans(0, text.length, LineBackgroundSpan::class.java)
|
|
56
|
+
if (spans.isEmpty()) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
canvas.save()
|
|
61
|
+
// From where a compound drawable is drawn to where the text is: the slot is
|
|
62
|
+
// pinned to the view and centred in the space between the compound paddings,
|
|
63
|
+
// while the layout hangs off the padding and scrolls.
|
|
64
|
+
val horizontalSpace = view.width - view.compoundPaddingLeft - view.compoundPaddingRight
|
|
65
|
+
canvas.translate(
|
|
66
|
+
(-view.scrollX - horizontalSpace / 2).toFloat(),
|
|
67
|
+
(view.totalPaddingTop - view.scrollY - view.height + view.paddingBottom).toFloat(),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
pass.painting = true
|
|
71
|
+
try {
|
|
72
|
+
paint(canvas, layout, text, spans)
|
|
73
|
+
} finally {
|
|
74
|
+
pass.painting = false
|
|
75
|
+
canvas.restore()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun paint(
|
|
80
|
+
canvas: Canvas,
|
|
81
|
+
layout: Layout,
|
|
82
|
+
text: Spanned,
|
|
83
|
+
spans: Array<out LineBackgroundSpan>
|
|
84
|
+
) {
|
|
85
|
+
// Only what the frame is about to show: a long document would otherwise pay
|
|
86
|
+
// for every line of it on every draw.
|
|
87
|
+
val firstLine: Int
|
|
88
|
+
val lastLine: Int
|
|
89
|
+
if (canvas.getClipBounds(clip)) {
|
|
90
|
+
firstLine = layout.getLineForVertical(clip.top)
|
|
91
|
+
lastLine = layout.getLineForVertical(clip.bottom)
|
|
92
|
+
} else {
|
|
93
|
+
firstLine = 0
|
|
94
|
+
lastLine = layout.lineCount - 1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
val paint = layout.paint
|
|
98
|
+
val width = layout.width
|
|
99
|
+
var top = layout.getLineTop(firstLine)
|
|
100
|
+
|
|
101
|
+
for (line in firstLine..lastLine) {
|
|
102
|
+
val start = layout.getLineStart(line)
|
|
103
|
+
val end = layout.getLineEnd(line)
|
|
104
|
+
// The next line's top rather than this line's bottom, so consecutive
|
|
105
|
+
// fills tile through the line spacing exactly as the layout's own pass
|
|
106
|
+
// makes them.
|
|
107
|
+
val bottom = layout.getLineTop(line + 1)
|
|
108
|
+
val baseline = bottom - layout.getLineDescent(line)
|
|
109
|
+
|
|
110
|
+
for (span in spans) {
|
|
111
|
+
// Ours only: anything else is still painted by the layout's own pass,
|
|
112
|
+
// where it belongs, and painting it here as well would double it.
|
|
113
|
+
if (span is MarkdownSpan &&
|
|
114
|
+
text.getSpanStart(span) < end &&
|
|
115
|
+
text.getSpanEnd(span) > start
|
|
116
|
+
) {
|
|
117
|
+
span.drawBackground(
|
|
118
|
+
canvas,
|
|
119
|
+
paint,
|
|
120
|
+
0,
|
|
121
|
+
width,
|
|
122
|
+
top,
|
|
123
|
+
baseline,
|
|
124
|
+
bottom,
|
|
125
|
+
text,
|
|
126
|
+
start,
|
|
127
|
+
end,
|
|
128
|
+
line,
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
top = bottom
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
override fun getIntrinsicWidth(): Int = 0
|
|
138
|
+
|
|
139
|
+
override fun getIntrinsicHeight(): Int = 0
|
|
140
|
+
|
|
141
|
+
override fun setAlpha(alpha: Int) = Unit
|
|
142
|
+
|
|
143
|
+
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
|
144
|
+
|
|
145
|
+
@Deprecated("Deprecated in Drawable", ReplaceWith("PixelFormat.TRANSLUCENT"))
|
|
146
|
+
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
|
147
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Whether the view is painting the markdown backgrounds itself.
|
|
5
|
+
*
|
|
6
|
+
* A `Text` lets the layout paint them, in the pass Android runs for
|
|
7
|
+
* `LineBackgroundSpan`. A `TextInput` cannot: that pass happens after the caret
|
|
8
|
+
* is drawn, so anything opaque in it hides the caret ([[MarkdownBackgroundPainter]]
|
|
9
|
+
* explains the rest). There the painter runs the spans itself, earlier, and this
|
|
10
|
+
* is what tells them which of the two moments they are in -- painting on both
|
|
11
|
+
* would put the background back over the caret.
|
|
12
|
+
*
|
|
13
|
+
* One instance per input. A spannable formatted for a `Text` carries none, and
|
|
14
|
+
* its spans paint whenever they are asked to.
|
|
15
|
+
*/
|
|
16
|
+
class MarkdownBackgroundPass {
|
|
17
|
+
/** True only while the painter is driving the spans. */
|
|
18
|
+
var painting = false
|
|
19
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
package app.getbullet.marcus
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import com.facebook.react.bridge.ReadableType
|
|
5
|
+
|
|
6
|
+
/** One placeholder character, and the markdown it was written as. */
|
|
7
|
+
data class MarkdownSubstitution(val index: Int, val text: String)
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* What a selection copies as.
|
|
11
|
+
*
|
|
12
|
+
* A view nested in a `Text` -- a drawn equation, an image -- is one U+FFFC in the spannable the
|
|
13
|
+
* `TextView` lays out, and U+FFFC is what the platform's own copy puts on the clipboard: a message
|
|
14
|
+
* with an equation in it arrives in the next application with a box where the maths was. So the
|
|
15
|
+
* copy is taken over and the placeholders are written back out as the source they stand for.
|
|
16
|
+
*
|
|
17
|
+
* Offsets are the ones JavaScript measured against the stripped text, which is the very string the
|
|
18
|
+
* `TextView` holds -- the ranges are measured against it too -- so a selection's start and end
|
|
19
|
+
* index into the same coordinates with nothing to remap.
|
|
20
|
+
*/
|
|
21
|
+
object MarkdownCopy {
|
|
22
|
+
|
|
23
|
+
@JvmStatic
|
|
24
|
+
fun read(array: ReadableArray?): List<MarkdownSubstitution> {
|
|
25
|
+
if (array == null || array.size() == 0) {
|
|
26
|
+
return emptyList()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
val substitutions = ArrayList<MarkdownSubstitution>(array.size())
|
|
30
|
+
|
|
31
|
+
for (i in 0 until array.size()) {
|
|
32
|
+
if (array.getType(i) != ReadableType.Map) {
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
val map = array.getMap(i) ?: continue
|
|
37
|
+
|
|
38
|
+
substitutions.add(
|
|
39
|
+
MarkdownSubstitution(index = map.getInt("index"), text = map.getString("text") ?: "")
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return substitutions
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The text between two offsets with every placeholder in it replaced by its source.
|
|
48
|
+
*
|
|
49
|
+
* Substitutions arrive in text order and each covers exactly one character, so one walk is
|
|
50
|
+
* enough. One that falls outside the selection is skipped rather than clipped: half an equation
|
|
51
|
+
* is not worth pasting, and a selection that stops in the middle of a drawing stops at its edge
|
|
52
|
+
* as far as the `TextView` is concerned anyway.
|
|
53
|
+
*/
|
|
54
|
+
fun substitute(
|
|
55
|
+
text: CharSequence,
|
|
56
|
+
start: Int,
|
|
57
|
+
end: Int,
|
|
58
|
+
substitutions: List<MarkdownSubstitution>,
|
|
59
|
+
): String {
|
|
60
|
+
val from = start.coerceIn(0, text.length)
|
|
61
|
+
val to = end.coerceIn(from, text.length)
|
|
62
|
+
val copied = StringBuilder(to - from)
|
|
63
|
+
var cursor = from
|
|
64
|
+
|
|
65
|
+
for (substitution in substitutions) {
|
|
66
|
+
val index = substitution.index
|
|
67
|
+
|
|
68
|
+
if (index < cursor) {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (index >= to) {
|
|
73
|
+
break
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
copied.append(text, cursor, index)
|
|
77
|
+
copied.append(substitution.text)
|
|
78
|
+
cursor = index + 1
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (cursor < to) {
|
|
82
|
+
copied.append(text, cursor, to)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return copied.toString()
|
|
86
|
+
}
|
|
87
|
+
}
|