react-native-enriched-markdown-scaffold 0.7.4-scaffold.9 → 1.0.2-scaffold.2
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 +54 -8
- package/ReactNativeEnrichedMarkdown.podspec +82 -73
- package/android/build.gradle +186 -1
- package/android/consumer-rules.pro +1 -1
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +9 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +24 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +8 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +9 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +35 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +886 -23
- package/android/src/main/baseline-prof.txt +1 -1
- package/android/src/main/cpp/jni-adapter.cpp +74 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +189 -13
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +50 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +10 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +42 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +82 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyPressEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +54 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +901 -462
- package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +101 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +49 -15
- package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +45 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +396 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +36 -9
- package/android/src/main/jni/CMakeLists.txt +53 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
- package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
- package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +7 -2
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +6 -4
- package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
- package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
- package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
- package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
- package/cpp/highlight/HighlightGrammars.hpp +28 -0
- package/cpp/highlight/code_highlight_podspec.rb +211 -0
- package/cpp/highlight/gen-registry.mjs +155 -0
- package/cpp/highlight/grammar-versions.json +159 -0
- package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
- package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
- package/cpp/parser/MD4CParser.cpp +173 -61
- package/cpp/parser/MD4CParser.hpp +1 -0
- package/cpp/parser/MarkdownASTNode.hpp +2 -1
- package/cpp/wasm/ASTSerializer.cpp +2 -0
- package/cpp/wasm/build.sh +1 -0
- package/cpp/wasm/md4c_wasm.cpp +3 -1
- package/docs/ACCESSIBILITY.md +14 -2
- package/docs/API_REFERENCE.md +234 -12
- package/docs/BREAKING_CHANGES.md +129 -0
- package/docs/CODE_HIGHLIGHT.md +133 -0
- package/docs/COPY_OPTIONS.md +47 -3
- package/docs/ELEMENTS_STRUCTURE.md +52 -4
- package/docs/IMAGE_CACHING.md +30 -0
- package/docs/INPUT.md +108 -11
- package/docs/LATEX_MATH.md +87 -45
- package/docs/MACOS.md +1 -1
- package/docs/MARKDOWN_STREAMING.md +27 -1
- package/docs/NATIVE_ASSETS.md +127 -0
- package/docs/RTL.md +1 -1
- package/docs/STYLES.md +46 -6
- package/docs/TESTING.md +112 -0
- package/docs/TEXT.md +16 -6
- package/docs/WEB.md +3 -1
- package/ios/EnrichedMarkdown.h +7 -0
- package/ios/EnrichedMarkdown.mm +284 -75
- package/ios/EnrichedMarkdownText.h +7 -0
- package/ios/EnrichedMarkdownText.mm +101 -73
- package/ios/attachments/ENRMImageAttachment.h +9 -0
- package/ios/attachments/ENRMImageAttachment.m +143 -40
- package/ios/attachments/ENRMMathInlineAttachment.h +2 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +48 -81
- package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +35 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +886 -23
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +131 -0
- package/ios/input/ENRMAutoLinkDetector.h +2 -1
- package/ios/input/ENRMAutoLinkDetector.mm +79 -41
- package/ios/input/ENRMBlockEditCoordinator.h +71 -0
- package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
- package/ios/input/ENRMBlockRange.h +28 -0
- package/ios/input/ENRMBlockRange.mm +30 -0
- package/ios/input/ENRMBlockStore.h +56 -0
- package/ios/input/ENRMBlockStore.mm +275 -0
- package/ios/input/ENRMClipboardCoordinator.h +45 -0
- package/ios/input/ENRMClipboardCoordinator.mm +120 -0
- package/ios/input/ENRMDetectorPipeline.h +2 -1
- package/ios/input/ENRMEditPipeline.h +76 -0
- package/ios/input/ENRMEditPipeline.mm +228 -0
- package/ios/input/ENRMEditSession.h +36 -0
- package/ios/input/ENRMEditSession.mm +63 -0
- package/ios/input/ENRMFormattingStore.h +17 -0
- package/ios/input/ENRMFormattingStore.mm +95 -105
- package/ios/input/ENRMInputBlockType.h +91 -0
- package/ios/input/ENRMInputBlockType.mm +5 -0
- package/ios/input/ENRMInputDecorationDrawer.h +18 -0
- package/ios/input/ENRMInputEventEmitter.h +56 -0
- package/ios/input/ENRMInputEventEmitter.mm +308 -0
- package/ios/input/ENRMInputFormatter.h +29 -69
- package/ios/input/ENRMInputFormatter.mm +216 -124
- package/ios/input/ENRMInputFormatterStyle.h +99 -0
- package/ios/input/ENRMInputFormatterStyle.mm +188 -0
- package/ios/input/ENRMInputLayoutManager.h +9 -0
- package/ios/input/ENRMInputLayoutManager.mm +30 -0
- package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
- package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
- package/ios/input/ENRMInputParser.h +5 -6
- package/ios/input/ENRMInputParser.mm +461 -178
- package/ios/input/ENRMInputRemend.mm +2 -2
- package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
- package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
- package/ios/input/ENRMInputTextView.mm +103 -8
- package/ios/input/ENRMInputTypingAttributesController.h +42 -0
- package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
- package/ios/input/ENRMLinkCoordinator.h +41 -0
- package/ios/input/ENRMLinkCoordinator.mm +89 -0
- package/ios/input/ENRMMarkdownSerializer.h +29 -5
- package/ios/input/ENRMMarkdownSerializer.mm +170 -48
- package/ios/input/ENRMMathAtom.h +26 -0
- package/ios/input/ENRMMathAtom.mm +12 -0
- package/ios/input/ENRMMentionCoordinator.h +45 -0
- package/ios/input/ENRMMentionCoordinator.mm +167 -0
- package/ios/input/ENRMRangeEditAdjustment.h +38 -0
- package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
- package/ios/input/ENRMRangeStoreUtils.h +39 -0
- package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
- package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
- package/ios/input/EnrichedMarkdownTextInput.h +7 -1
- package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
- package/ios/input/InputStylePropsUtils.h +109 -68
- package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
- package/ios/input/styles/ENRMBlockHandler.h +46 -0
- package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
- package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
- package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
- package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
- package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
- package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
- package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
- package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
- package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
- package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
- package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
- package/ios/internals/MeasurementCache.h +33 -7
- package/ios/internals/ShadowMeasurementUtils.h +63 -58
- package/ios/math/ENRMMathChipController.h +74 -0
- package/ios/math/ENRMMathChipController.mm +476 -0
- package/ios/math/ENRMRaTeXBridge.swift +4 -1
- package/ios/parser/ENRMMarkdownParser.h +1 -8
- package/ios/parser/ENRMMarkdownParser.mm +2 -11
- package/ios/parser/MarkdownASTNode.h +2 -1
- package/ios/parser/MarkdownParserBridge.mm +4 -0
- package/ios/renderer/AttributedRenderer.m +20 -2
- package/ios/renderer/BaseRenderer.h +17 -2
- package/ios/renderer/BaseRenderer.m +30 -0
- package/ios/renderer/BlockquoteRenderer.h +1 -1
- package/ios/renderer/BlockquoteRenderer.m +144 -35
- package/ios/renderer/CodeBlockRenderer.h +1 -1
- package/ios/renderer/CodeBlockRenderer.m +27 -23
- package/ios/renderer/CodeRenderer.h +1 -1
- package/ios/renderer/CodeRenderer.m +3 -1
- package/ios/renderer/ENRMImageRenderer.h +1 -1
- package/ios/renderer/ENRMImageRenderer.m +5 -1
- package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
- package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
- package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
- package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
- package/ios/renderer/EmphasisRenderer.h +1 -1
- package/ios/renderer/EmphasisRenderer.m +3 -1
- package/ios/renderer/HeadingRenderer.h +1 -1
- package/ios/renderer/HeadingRenderer.m +13 -6
- package/ios/renderer/HighlightRenderer.h +1 -1
- package/ios/renderer/HighlightRenderer.m +3 -1
- package/ios/renderer/LinkRenderer.h +1 -1
- package/ios/renderer/LinkRenderer.m +3 -1
- package/ios/renderer/ListItemRenderer.h +13 -1
- package/ios/renderer/ListItemRenderer.m +102 -44
- package/ios/renderer/ListRenderer.h +2 -2
- package/ios/renderer/ListRenderer.m +63 -25
- package/ios/renderer/ParagraphRenderer.h +1 -1
- package/ios/renderer/ParagraphRenderer.m +16 -8
- package/ios/renderer/RenderContext.h +10 -0
- package/ios/renderer/RenderContext.m +44 -0
- package/ios/renderer/RendererFactory.m +14 -0
- package/ios/renderer/StrikethroughRenderer.h +1 -1
- package/ios/renderer/StrikethroughRenderer.m +3 -1
- package/ios/renderer/StrongRenderer.h +1 -1
- package/ios/renderer/StrongRenderer.m +3 -1
- package/ios/renderer/SubscriptRenderer.h +1 -1
- package/ios/renderer/SubscriptRenderer.m +3 -1
- package/ios/renderer/SuperscriptRenderer.h +1 -1
- package/ios/renderer/SuperscriptRenderer.m +3 -1
- package/ios/renderer/TextRenderer.h +2 -2
- package/ios/renderer/TextRenderer.m +3 -1
- package/ios/renderer/ThematicBreakRenderer.h +1 -1
- package/ios/renderer/ThematicBreakRenderer.m +3 -1
- package/ios/renderer/UnderlineRenderer.h +1 -1
- package/ios/renderer/UnderlineRenderer.m +3 -1
- package/ios/styles/StyleConfig.h +22 -0
- package/ios/styles/StyleConfig.mm +132 -0
- package/ios/utils/BlockquoteBorder.h +6 -0
- package/ios/utils/BlockquoteBorder.m +249 -52
- package/ios/utils/CodeBlockBackground.m +16 -2
- package/ios/utils/ENRMAtomicSize.h +65 -0
- package/ios/utils/ENRMBlockMenu.h +57 -0
- package/ios/utils/ENRMCodeBlockContent.h +37 -0
- package/ios/utils/ENRMCodeBlockContent.mm +79 -0
- package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
- package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
- package/ios/utils/ENRMFeatureFlags.h +7 -0
- package/ios/utils/ENRMImageDownloader.h +11 -1
- package/ios/utils/ENRMImageDownloader.m +60 -16
- package/ios/utils/ENRMLocalImageLoader.h +31 -0
- package/ios/utils/ENRMLocalImageLoader.m +68 -0
- package/ios/utils/ENRMMathFallback.h +26 -0
- package/ios/utils/ENRMMathFallback.m +18 -0
- package/ios/utils/ENRMTextViewSetup.h +35 -17
- package/ios/utils/EditMenuUtils.h +22 -5
- package/ios/utils/EditMenuUtils.m +53 -9
- package/ios/utils/ImageRequestHeaderUtils.h +35 -0
- package/ios/utils/LastElementUtils.h +1 -0
- package/ios/utils/ListMarkerDrawer.m +29 -42
- package/ios/utils/MarkdownASTSerializer.m +4 -0
- package/ios/utils/ParagraphStyleUtils.h +5 -0
- package/ios/utils/ParagraphStyleUtils.m +77 -17
- package/ios/utils/RenderedMarkdownSegment.h +13 -1
- package/ios/utils/RenderedMarkdownSegment.m +20 -0
- package/ios/utils/SegmentRenderer.m +17 -4
- package/ios/utils/StreamingMarkdownFilter.h +11 -1
- package/ios/utils/StreamingMarkdownFilter.m +98 -2
- package/ios/utils/StylePropsUtils.h +63 -0
- package/ios/utils/TaskListTapUtils.m +24 -0
- package/ios/views/ENRMCodeBlockContainerView.h +53 -0
- package/ios/views/ENRMCodeBlockContainerView.m +559 -0
- package/ios/views/ENRMMathContainerView.h +16 -0
- package/ios/views/ENRMMathContainerView.m +74 -19
- package/ios/views/TableContainerView.h +22 -0
- package/ios/views/TableContainerView.m +261 -175
- package/jest.d.ts +1 -0
- package/jest.js +5 -0
- package/lib/module/EnrichedMarkdownNativeComponent.ts +73 -0
- package/lib/module/EnrichedMarkdownTextInput.js +84 -5
- package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
- package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +74 -0
- package/lib/module/headingDefaults.js +34 -0
- package/lib/module/headingDefaults.js.map +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/jest/index.js +191 -0
- package/lib/module/jest/index.js.map +1 -0
- package/lib/module/native/EnrichedMarkdownText.js +37 -5
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.js +81 -19
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +56 -18
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
- package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
- package/lib/module/normalizeMenuItem.js +1 -1
- package/lib/module/utils/textInputState.js +26 -0
- package/lib/module/utils/textInputState.js.map +1 -0
- package/lib/module/web/EnrichedMarkdownText.js +9 -5
- package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/web/parseMarkdown.js +4 -3
- package/lib/module/web/parseMarkdown.js.map +1 -1
- package/lib/module/web/renderers/InlineRenderers.js +6 -0
- package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
- package/lib/module/web/renderers/ListRenderers.js +7 -2
- package/lib/module/web/renderers/ListRenderers.js.map +1 -1
- package/lib/module/web/renderers/index.js +7 -4
- package/lib/module/web/renderers/index.js.map +1 -1
- package/lib/module/web/styles.js +83 -6
- package/lib/module/web/styles.js.map +1 -1
- package/lib/module/web/utils.js +1 -0
- package/lib/module/web/utils.js.map +1 -1
- package/lib/module/web/wasm/md4c.js +0 -0
- package/lib/module/web/wasm/md4c.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +66 -0
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +66 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/headingDefaults.d.ts +9 -0
- package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +1 -1
- package/lib/typescript/src/index.web.d.ts.map +1 -1
- package/lib/typescript/src/jest/index.d.ts +6 -0
- package/lib/typescript/src/jest/index.d.ts.map +1 -0
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyle.d.ts +72 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +27 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +104 -9
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +19 -0
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +19 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/lib/typescript/src/utils/textInputState.d.ts +24 -0
- package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
- package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/index.d.ts +2 -1
- package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
- package/lib/typescript/src/web/styles.d.ts +2 -1
- package/lib/typescript/src/web/styles.d.ts.map +1 -1
- package/lib/typescript/src/web/types.d.ts +6 -2
- package/lib/typescript/src/web/types.d.ts.map +1 -1
- package/lib/typescript/src/web/utils.d.ts.map +1 -1
- package/package.json +36 -9
- package/postinstall.mjs +131 -0
- package/ratex-version.json +21 -0
- package/src/EnrichedMarkdownNativeComponent.ts +73 -0
- package/src/EnrichedMarkdownTextInput.tsx +159 -8
- package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
- package/src/EnrichedMarkdownTextNativeComponent.ts +74 -0
- package/src/headingDefaults.ts +21 -0
- package/src/index.tsx +9 -0
- package/src/index.web.tsx +1 -0
- package/src/jest/index.tsx +215 -0
- package/src/native/EnrichedMarkdownText.tsx +53 -2
- package/src/normalizeMarkdownStyle.ts +102 -16
- package/src/normalizeMarkdownStyle.web.ts +63 -15
- package/src/normalizeMarkdownTextInputStyle.ts +110 -35
- package/src/normalizeMenuItem.ts +1 -1
- package/src/types/MarkdownStyle.ts +74 -0
- package/src/types/MarkdownStyleInternal.ts +39 -0
- package/src/types/MarkdownTextProps.ts +101 -9
- package/src/types/MarkdownTextProps.web.ts +19 -0
- package/src/types/events.ts +21 -0
- package/src/utils/textInputState.ts +35 -0
- package/src/web/EnrichedMarkdownText.tsx +16 -2
- package/src/web/parseMarkdown.ts +6 -2
- package/src/web/renderers/InlineRenderers.tsx +5 -0
- package/src/web/renderers/ListRenderers.tsx +14 -2
- package/src/web/renderers/index.tsx +6 -2
- package/src/web/styles.ts +89 -5
- package/src/web/types.ts +6 -1
- package/src/web/utils.ts +1 -0
- package/src/web/wasm/md4c.js +0 -0
- package/vendor-grammars.mjs +511 -0
- package/vendor-ratex.mjs +173 -0
- package/app.plugin.js +0 -2
- package/plugin/build/withAndroidMath.js +0 -19
- package/plugin/build/withIosMath.js +0 -28
- package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
- package/plugin/src/withAndroidMath.ts +0 -24
- package/plugin/src/withIosMath.ts +0 -35
- package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
- package/plugin/tsconfig.build.json +0 -16
|
@@ -80,6 +80,7 @@ class RendererFactory(
|
|
|
80
80
|
|
|
81
81
|
private val textRenderer = TextRenderer()
|
|
82
82
|
private val lineBreakRenderer = LineBreakRenderer()
|
|
83
|
+
private val softBreakRenderer = SoftBreakRenderer()
|
|
83
84
|
|
|
84
85
|
private val renderers: Map<MarkdownASTNode.NodeType, NodeRenderer> by lazy {
|
|
85
86
|
buildMap {
|
|
@@ -103,13 +104,20 @@ class RendererFactory(
|
|
|
103
104
|
put(MarkdownASTNode.NodeType.Code, CodeRenderer(config))
|
|
104
105
|
put(MarkdownASTNode.NodeType.Image, ImageRenderer())
|
|
105
106
|
put(MarkdownASTNode.NodeType.LineBreak, lineBreakRenderer)
|
|
107
|
+
put(MarkdownASTNode.NodeType.SoftBreak, softBreakRenderer)
|
|
106
108
|
put(MarkdownASTNode.NodeType.ThematicBreak, ThematicBreakRenderer(config))
|
|
107
109
|
put(MarkdownASTNode.NodeType.Spoiler, SpoilerRenderer())
|
|
108
110
|
if (FeatureFlags.IS_MATH_ENABLED) {
|
|
109
111
|
try {
|
|
110
112
|
val mathInlineRendererClass = Class.forName("com.swmansion.enriched.markdown.renderer.MathInlineRenderer")
|
|
111
113
|
val constructor = mathInlineRendererClass.getConstructor(RendererConfig::class.java, Context::class.java)
|
|
112
|
-
|
|
114
|
+
val mathInlineRenderer = constructor.newInstance(config, context) as NodeRenderer
|
|
115
|
+
put(MarkdownASTNode.NodeType.LatexMathInline, mathInlineRenderer)
|
|
116
|
+
// Isolated display math is promoted to a block segment in the parser
|
|
117
|
+
// (see promoteDisplayMathFromParagraphs). What reaches the factory is
|
|
118
|
+
// genuinely mid-line display math (e.g. `a $$x$$ b`); render it inline
|
|
119
|
+
// rather than dropping it via the TextRenderer fallback.
|
|
120
|
+
put(MarkdownASTNode.NodeType.LatexMathDisplay, mathInlineRenderer)
|
|
113
121
|
} catch (_: Exception) {
|
|
114
122
|
// math not available
|
|
115
123
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.swmansion.enriched.markdown.renderer
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import com.swmansion.enriched.markdown.parser.MarkdownASTNode
|
|
5
|
+
|
|
6
|
+
class SoftBreakRenderer : NodeRenderer {
|
|
7
|
+
override fun render(
|
|
8
|
+
node: MarkdownASTNode,
|
|
9
|
+
builder: SpannableStringBuilder,
|
|
10
|
+
onLinkPress: ((String) -> Unit)?,
|
|
11
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
12
|
+
factory: RendererFactory,
|
|
13
|
+
) {
|
|
14
|
+
builder.append(" ")
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
package com.swmansion.enriched.markdown.renderer
|
|
2
2
|
|
|
3
|
+
import android.content.res.AssetManager
|
|
3
4
|
import android.graphics.Typeface
|
|
5
|
+
import com.facebook.react.common.ReactConstants
|
|
6
|
+
import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
|
|
4
7
|
import com.swmansion.enriched.markdown.styles.LinkVariantEntry
|
|
5
8
|
import com.swmansion.enriched.markdown.styles.StyleConfig
|
|
6
9
|
|
|
@@ -8,6 +11,8 @@ import com.swmansion.enriched.markdown.styles.StyleConfig
|
|
|
8
11
|
class SpanStyleCache(
|
|
9
12
|
style: StyleConfig,
|
|
10
13
|
) {
|
|
14
|
+
private val assetManager: AssetManager = style.assetManager
|
|
15
|
+
|
|
11
16
|
// Colors to preserve when applying inline styles (links, code, strong, emphasis)
|
|
12
17
|
val colorsToPreserve: IntArray = buildColorsToPreserve(style)
|
|
13
18
|
|
|
@@ -95,36 +100,34 @@ class SpanStyleCache(
|
|
|
95
100
|
return compiledVariantPatterns.firstOrNull { (regex, _) -> regex.containsMatchIn(url) }?.second
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Cached typeface for font family + style (BOLD, ITALIC, BOLD_ITALIC).
|
|
105
|
+
*
|
|
106
|
+
* Loads the base custom font at its NORMAL weight (via applyStyles/ReactFontManager)
|
|
107
|
+
* so the bundled assets/fonts file resolves, then synthesizes bold/italic on that real
|
|
108
|
+
* typeface. Requesting bold/italic directly makes ReactFontManager look for `_bold`/
|
|
109
|
+
* `_italic` asset variants that single-file custom fonts don't have — and it then falls
|
|
110
|
+
* back to a default system face, dropping the custom font entirely.
|
|
111
|
+
*/
|
|
112
|
+
fun getTypeface(
|
|
113
|
+
fontFamily: String,
|
|
114
|
+
style: Int,
|
|
115
|
+
): Typeface =
|
|
116
|
+
typefaceCache.getOrPut("family|$fontFamily|$style") {
|
|
117
|
+
val base =
|
|
118
|
+
applyStyles(
|
|
119
|
+
null,
|
|
120
|
+
ReactConstants.UNSET,
|
|
121
|
+
ReactConstants.UNSET,
|
|
122
|
+
fontFamily.takeIf { it.isNotEmpty() },
|
|
123
|
+
assetManager,
|
|
124
|
+
)
|
|
125
|
+
if (style == Typeface.NORMAL) base else Typeface.create(base, style)
|
|
126
|
+
}
|
|
127
|
+
|
|
98
128
|
companion object {
|
|
99
129
|
private val typefaceCache = mutableMapOf<String, Typeface>()
|
|
100
130
|
|
|
101
|
-
/** Cached typeface for font family + style (BOLD, ITALIC, BOLD_ITALIC) */
|
|
102
|
-
fun getTypeface(
|
|
103
|
-
fontFamily: String,
|
|
104
|
-
style: Int,
|
|
105
|
-
): Typeface =
|
|
106
|
-
typefaceCache.getOrPut("$fontFamily|$style") {
|
|
107
|
-
val base =
|
|
108
|
-
fontFamily
|
|
109
|
-
.takeIf { it.isNotEmpty() }
|
|
110
|
-
?.let { Typeface.create(it, Typeface.NORMAL) }
|
|
111
|
-
?: Typeface.DEFAULT
|
|
112
|
-
Typeface.create(base, style)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Cached typeface using weight string (e.g., "bold", "700") */
|
|
116
|
-
fun getTypefaceWithWeight(
|
|
117
|
-
fontFamily: String,
|
|
118
|
-
fontWeight: String,
|
|
119
|
-
): Typeface {
|
|
120
|
-
val style =
|
|
121
|
-
when (fontWeight.lowercase()) {
|
|
122
|
-
"bold", "700", "800", "900" -> Typeface.BOLD
|
|
123
|
-
else -> Typeface.NORMAL
|
|
124
|
-
}
|
|
125
|
-
return getTypeface(fontFamily, style)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
131
|
/** Cached monospace typeface preserving bold/italic */
|
|
129
132
|
fun getMonospaceTypeface(currentStyle: Int): Typeface =
|
|
130
133
|
typefaceCache.getOrPut("monospace|$currentStyle") {
|
|
@@ -22,11 +22,20 @@ abstract class BaseListSpan(
|
|
|
22
22
|
protected val blockStyle: BlockStyle,
|
|
23
23
|
protected val marginLeft: Float,
|
|
24
24
|
protected val gapWidth: Float,
|
|
25
|
+
internal val drawsMarker: Boolean = true,
|
|
25
26
|
) : MetricAffectingSpan(),
|
|
26
27
|
LeadingMarginSpan {
|
|
27
28
|
private var cachedText: CharSequence? = null
|
|
28
29
|
private var cachedHasDeeperSpanByPosition = mutableMapOf<Int, Boolean>()
|
|
29
30
|
|
|
31
|
+
val markerFontMetrics: Paint.FontMetrics by lazy {
|
|
32
|
+
TextPaint()
|
|
33
|
+
.apply {
|
|
34
|
+
applyBlockStyleFont(blockStyle, context)
|
|
35
|
+
textSize = blockStyle.fontSize
|
|
36
|
+
}.fontMetrics
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
protected abstract fun getMarkerWidth(): Float
|
|
31
40
|
|
|
32
41
|
override fun updateMeasureState(textPaint: TextPaint) = applyTextStyle(textPaint)
|
|
@@ -55,6 +64,7 @@ abstract class BaseListSpan(
|
|
|
55
64
|
first: Boolean,
|
|
56
65
|
layout: Layout?,
|
|
57
66
|
) {
|
|
67
|
+
if (!drawsMarker) return
|
|
58
68
|
if (!first || shouldSkipDrawing(text, start) || !hasContent(text, start, end)) return
|
|
59
69
|
|
|
60
70
|
// Only draw the marker on the true first line of this span.
|
|
@@ -62,6 +72,20 @@ abstract class BaseListSpan(
|
|
|
62
72
|
// but only the line at the span start should get a bullet/number.
|
|
63
73
|
if (text is Spanned && text.getSpanStart(this) != start) return
|
|
64
74
|
|
|
75
|
+
drawMarkerAt(canvas, paint, x, dir, top, baseline, bottom, layout, start)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fun drawMarkerAt(
|
|
79
|
+
canvas: Canvas,
|
|
80
|
+
paint: Paint,
|
|
81
|
+
x: Int,
|
|
82
|
+
dir: Int,
|
|
83
|
+
top: Int,
|
|
84
|
+
baseline: Int,
|
|
85
|
+
bottom: Int,
|
|
86
|
+
layout: Layout?,
|
|
87
|
+
start: Int,
|
|
88
|
+
) {
|
|
65
89
|
val originalStyle = paint.style
|
|
66
90
|
val originalColor = paint.color
|
|
67
91
|
drawMarker(canvas, paint, x, dir, top, baseline, bottom, layout, start)
|
|
@@ -5,6 +5,8 @@ import android.content.Context
|
|
|
5
5
|
import android.graphics.Canvas
|
|
6
6
|
import android.graphics.Color
|
|
7
7
|
import android.graphics.Paint
|
|
8
|
+
import android.graphics.Path
|
|
9
|
+
import android.graphics.RectF
|
|
8
10
|
import android.graphics.Typeface
|
|
9
11
|
import android.text.Layout
|
|
10
12
|
import android.text.Spanned
|
|
@@ -12,6 +14,7 @@ import android.text.TextPaint
|
|
|
12
14
|
import android.text.style.LeadingMarginSpan
|
|
13
15
|
import android.text.style.LineBackgroundSpan
|
|
14
16
|
import android.text.style.MetricAffectingSpan
|
|
17
|
+
import androidx.core.graphics.withSave
|
|
15
18
|
import com.swmansion.enriched.markdown.renderer.BlockStyle
|
|
16
19
|
import com.swmansion.enriched.markdown.renderer.SpanStyleCache
|
|
17
20
|
import com.swmansion.enriched.markdown.styles.BlockquoteStyle
|
|
@@ -37,7 +40,13 @@ class BlockquoteSpan(
|
|
|
37
40
|
|
|
38
41
|
// Cache for shouldSkipDrawing to avoid repeated getSpans() calls during draw passes
|
|
39
42
|
private var cachedText: CharSequence? = null
|
|
40
|
-
private var
|
|
43
|
+
private var cachedSpansByPosition = mutableMapOf<Int, Array<BlockquoteSpan>>()
|
|
44
|
+
private var boxLeft = 0f
|
|
45
|
+
private var boxRight = 0f
|
|
46
|
+
|
|
47
|
+
private val path = Path()
|
|
48
|
+
private val rect = RectF()
|
|
49
|
+
private val radiiArray = FloatArray(8)
|
|
41
50
|
|
|
42
51
|
override fun updateMeasureState(tp: TextPaint) = applyTextStyle(tp)
|
|
43
52
|
|
|
@@ -63,13 +72,56 @@ class BlockquoteSpan(
|
|
|
63
72
|
if (shouldSkipDrawing(text, start)) return
|
|
64
73
|
|
|
65
74
|
val borderPaint = configureBorderPaint()
|
|
66
|
-
val
|
|
67
|
-
val
|
|
75
|
+
val radius = blockquoteStyle.borderRadius
|
|
76
|
+
val spanned = text as? Spanned
|
|
77
|
+
|
|
78
|
+
if (spanned == null) {
|
|
79
|
+
drawBorders(c, x, dir, top, bottom, borderPaint)
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
val rootSpan = spanAtMinDepth(spanned, start)
|
|
84
|
+
val clipToRoot =
|
|
85
|
+
radius > 0f && boxRight > boxLeft && rootSpan != null && isBoundaryLine(spanned, start, end, rootSpan)
|
|
86
|
+
|
|
87
|
+
val padding = blockquoteStyle.padding
|
|
88
|
+
var topInset = 0f
|
|
89
|
+
var bottomInset = 0f
|
|
68
90
|
|
|
69
91
|
for (level in 0..depth) {
|
|
70
92
|
val borderX = x + (levelSpacing * level * dir)
|
|
71
93
|
val borderRight = borderX + (blockquoteStyle.borderWidth * dir)
|
|
72
|
-
|
|
94
|
+
val stripeLeft = minOf(borderX, borderRight)
|
|
95
|
+
val stripeRight = maxOf(borderX, borderRight)
|
|
96
|
+
val stripeTop = top.toFloat() + topInset
|
|
97
|
+
val stripeBottom = bottom.toFloat() - bottomInset
|
|
98
|
+
|
|
99
|
+
val levelSpan = if (level == 0) rootSpan else spanAtDepth(spanned, start, level)
|
|
100
|
+
val clipToOwn =
|
|
101
|
+
radius > 0f && level > 0 && levelSpan != null && isBoundaryLine(spanned, start, end, levelSpan)
|
|
102
|
+
|
|
103
|
+
if (!clipToRoot && !clipToOwn) {
|
|
104
|
+
c.drawRect(stripeLeft, stripeTop, stripeRight, stripeBottom, borderPaint)
|
|
105
|
+
} else {
|
|
106
|
+
c.withSave {
|
|
107
|
+
if (clipToRoot) {
|
|
108
|
+
buildBoundaryPath(spanned, start, end, rootSpan!!, boxLeft, top.toFloat(), boxRight, bottom.toFloat())
|
|
109
|
+
clipPath(path)
|
|
110
|
+
}
|
|
111
|
+
if (clipToOwn) {
|
|
112
|
+
val clipLeft = if (dir >= 0) stripeLeft else boxLeft
|
|
113
|
+
val clipRight = if (dir >= 0) boxRight else stripeRight
|
|
114
|
+
buildBoundaryPath(spanned, start, end, levelSpan!!, clipLeft, stripeTop, clipRight, stripeBottom)
|
|
115
|
+
clipPath(path)
|
|
116
|
+
}
|
|
117
|
+
drawRect(stripeLeft, stripeTop, stripeRight, stripeBottom, borderPaint)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (padding > 0 && levelSpan != null) {
|
|
122
|
+
if (start == spanned.getSpanStart(levelSpan)) topInset += padding
|
|
123
|
+
if (isLastLineOf(spanned, end, levelSpan)) bottomInset += padding
|
|
124
|
+
}
|
|
73
125
|
}
|
|
74
126
|
}
|
|
75
127
|
|
|
@@ -87,7 +139,40 @@ class BlockquoteSpan(
|
|
|
87
139
|
lineNum: Int,
|
|
88
140
|
) {
|
|
89
141
|
if (shouldSkipDrawing(text, start)) return
|
|
90
|
-
|
|
142
|
+
|
|
143
|
+
boxLeft = left.toFloat()
|
|
144
|
+
boxRight = right.toFloat()
|
|
145
|
+
|
|
146
|
+
val bgColor = blockquoteStyle.backgroundColor?.takeIf { it != Color.TRANSPARENT } ?: return
|
|
147
|
+
val backgroundPaint = configureBackgroundPaint(bgColor)
|
|
148
|
+
val radius = blockquoteStyle.borderRadius
|
|
149
|
+
val rootSpan = (text as? Spanned)?.let { spanAtMinDepth(it, start) }
|
|
150
|
+
|
|
151
|
+
if (radius <= 0f || rootSpan == null) {
|
|
152
|
+
canvas.drawRect(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat(), backgroundPaint)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
buildBoundaryPath(text as Spanned, start, end, rootSpan, left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
|
|
157
|
+
canvas.drawPath(path, backgroundPaint)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private fun drawBorders(
|
|
161
|
+
c: Canvas,
|
|
162
|
+
x: Int,
|
|
163
|
+
dir: Int,
|
|
164
|
+
top: Int,
|
|
165
|
+
bottom: Int,
|
|
166
|
+
borderPaint: Paint,
|
|
167
|
+
) {
|
|
168
|
+
val borderTop = top.toFloat()
|
|
169
|
+
val borderBottom = bottom.toFloat()
|
|
170
|
+
|
|
171
|
+
for (level in 0..depth) {
|
|
172
|
+
val borderX = x + (levelSpacing * level * dir)
|
|
173
|
+
val borderRight = borderX + (blockquoteStyle.borderWidth * dir)
|
|
174
|
+
c.drawRect(minOf(borderX, borderRight), borderTop, maxOf(borderX, borderRight), borderBottom, borderPaint)
|
|
175
|
+
}
|
|
91
176
|
}
|
|
92
177
|
|
|
93
178
|
@SuppressLint("WrongConstant") // Result of mask is always valid: 0, 1, 2, or 3
|
|
@@ -118,35 +203,100 @@ class BlockquoteSpan(
|
|
|
118
203
|
color = bgColor
|
|
119
204
|
}
|
|
120
205
|
|
|
206
|
+
private fun spansAt(
|
|
207
|
+
text: Spanned,
|
|
208
|
+
start: Int,
|
|
209
|
+
): Array<BlockquoteSpan> {
|
|
210
|
+
if (cachedText !== text) {
|
|
211
|
+
cachedText = text
|
|
212
|
+
cachedSpansByPosition.clear()
|
|
213
|
+
}
|
|
214
|
+
return cachedSpansByPosition.getOrPut(start) {
|
|
215
|
+
text.getSpans(start, start + 1, BlockquoteSpan::class.java)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
121
219
|
private fun shouldSkipDrawing(
|
|
122
220
|
text: CharSequence?,
|
|
123
221
|
start: Int,
|
|
124
222
|
): Boolean {
|
|
125
223
|
if (text !is Spanned) return false
|
|
224
|
+
val maxDepth = spansAt(text, start).maxOfOrNull { it.depth } ?: -1
|
|
225
|
+
return maxDepth > depth
|
|
226
|
+
}
|
|
126
227
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
228
|
+
private fun spanAtMinDepth(
|
|
229
|
+
text: Spanned,
|
|
230
|
+
start: Int,
|
|
231
|
+
): BlockquoteSpan? = spansAt(text, start).minByOrNull { it.depth }
|
|
131
232
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
233
|
+
private fun spanAtDepth(
|
|
234
|
+
text: Spanned,
|
|
235
|
+
start: Int,
|
|
236
|
+
level: Int,
|
|
237
|
+
): BlockquoteSpan? = spansAt(text, start).firstOrNull { it.depth == level }
|
|
137
238
|
|
|
138
|
-
|
|
239
|
+
/**
|
|
240
|
+
* The span range can include trailing '\n'(s) that form no visible line (e.g. a
|
|
241
|
+
* paragraph break closing the quote), so the last drawn line ends before getSpanEnd;
|
|
242
|
+
* this compares against the end of visible content instead.
|
|
243
|
+
*/
|
|
244
|
+
private fun isLastLineOf(
|
|
245
|
+
text: Spanned,
|
|
246
|
+
lineEnd: Int,
|
|
247
|
+
box: BlockquoteSpan,
|
|
248
|
+
): Boolean {
|
|
249
|
+
var boxEnd = text.getSpanEnd(box)
|
|
250
|
+
while (boxEnd > 0 && text[boxEnd - 1] == '\n') {
|
|
251
|
+
boxEnd--
|
|
252
|
+
}
|
|
253
|
+
return lineEnd >= boxEnd
|
|
139
254
|
}
|
|
140
255
|
|
|
141
|
-
private fun
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
256
|
+
private fun isBoundaryLine(
|
|
257
|
+
text: Spanned,
|
|
258
|
+
lineStart: Int,
|
|
259
|
+
lineEnd: Int,
|
|
260
|
+
box: BlockquoteSpan,
|
|
261
|
+
): Boolean {
|
|
262
|
+
val boxStart = text.getSpanStart(box)
|
|
263
|
+
val boxEnd = text.getSpanEnd(box)
|
|
264
|
+
if (boxStart !in 0 until boxEnd) return false
|
|
265
|
+
return lineStart == boxStart || isLastLineOf(text, lineEnd, box)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private fun buildBoundaryPath(
|
|
269
|
+
text: Spanned,
|
|
270
|
+
lineStart: Int,
|
|
271
|
+
lineEnd: Int,
|
|
272
|
+
box: BlockquoteSpan,
|
|
273
|
+
left: Float,
|
|
274
|
+
top: Float,
|
|
275
|
+
right: Float,
|
|
276
|
+
bottom: Float,
|
|
147
277
|
) {
|
|
148
|
-
val
|
|
149
|
-
|
|
150
|
-
|
|
278
|
+
val boxStart = text.getSpanStart(box)
|
|
279
|
+
|
|
280
|
+
val isFirstLine = lineStart == boxStart
|
|
281
|
+
val isLastLine = isLastLineOf(text, lineEnd, box)
|
|
282
|
+
|
|
283
|
+
val radius = blockquoteStyle.borderRadius
|
|
284
|
+
radiiArray.fill(0f)
|
|
285
|
+
if (isFirstLine) {
|
|
286
|
+
radiiArray[0] = radius
|
|
287
|
+
radiiArray[1] = radius // Top-Left
|
|
288
|
+
radiiArray[2] = radius
|
|
289
|
+
radiiArray[3] = radius // Top-Right
|
|
290
|
+
}
|
|
291
|
+
if (isLastLine) {
|
|
292
|
+
radiiArray[4] = radius
|
|
293
|
+
radiiArray[5] = radius // Bottom-Right
|
|
294
|
+
radiiArray[6] = radius
|
|
295
|
+
radiiArray[7] = radius // Bottom-Left
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
rect.set(left, top, right, bottom)
|
|
299
|
+
path.reset()
|
|
300
|
+
path.addRoundRect(rect, radiiArray, Path.Direction.CW)
|
|
151
301
|
}
|
|
152
302
|
}
|
|
@@ -7,6 +7,7 @@ import android.graphics.RectF
|
|
|
7
7
|
import android.text.Spanned
|
|
8
8
|
import android.text.StaticLayout
|
|
9
9
|
import android.text.TextPaint
|
|
10
|
+
import android.text.style.LeadingMarginSpan
|
|
10
11
|
import android.text.style.LineBackgroundSpan
|
|
11
12
|
import com.swmansion.enriched.markdown.styles.StyleConfig
|
|
12
13
|
import kotlin.math.max
|
|
@@ -58,8 +59,9 @@ class CodeBackgroundSpan(
|
|
|
58
59
|
|
|
59
60
|
// 2. Calculate coordinates
|
|
60
61
|
val finalBottom = adjustBottomForMargin(text, end, bottom)
|
|
61
|
-
val
|
|
62
|
-
val
|
|
62
|
+
val leadingMargin = leadingMarginAt(text, start)
|
|
63
|
+
val startX = if (isFirst) getHorizontalOffset(text, start, end, spanStart, p, leadingMargin) + left else left.toFloat() + leadingMargin
|
|
64
|
+
val endX = if (isLast) getHorizontalOffset(text, start, end, spanEnd, p, leadingMargin) + left else right.toFloat()
|
|
63
65
|
|
|
64
66
|
rect.set(min(startX, endX), top.toFloat(), max(startX, endX), finalBottom.toFloat())
|
|
65
67
|
|
|
@@ -71,14 +73,23 @@ class CodeBackgroundSpan(
|
|
|
71
73
|
drawShapes(canvas, isFirst, isLast)
|
|
72
74
|
}
|
|
73
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Returns the x position of [index] relative to the line's left edge, including any
|
|
78
|
+
* leading margin. The measuring StaticLayout is built from a subSequence that keeps
|
|
79
|
+
* all spans, so LeadingMarginSpans (lists, blockquotes) are already applied to
|
|
80
|
+
* getPrimaryHorizontal; adding the margin again on top would shift the background
|
|
81
|
+
* right by the indent. The margin is only added explicitly in the early-return case,
|
|
82
|
+
* where no layout is built.
|
|
83
|
+
*/
|
|
74
84
|
private fun getHorizontalOffset(
|
|
75
85
|
text: CharSequence,
|
|
76
86
|
lineStart: Int,
|
|
77
87
|
lineEnd: Int,
|
|
78
88
|
index: Int,
|
|
79
89
|
paint: Paint,
|
|
90
|
+
leadingMargin: Int,
|
|
80
91
|
): Float {
|
|
81
|
-
if (index <= lineStart) return
|
|
92
|
+
if (index <= lineStart) return leadingMargin.toFloat()
|
|
82
93
|
val lineText = text.subSequence(lineStart, lineEnd)
|
|
83
94
|
val textPaint = paint as? TextPaint ?: TextPaint(paint)
|
|
84
95
|
val layout = StaticLayout.Builder.obtain(lineText, 0, lineText.length, textPaint, 10000).build()
|
|
@@ -164,6 +175,19 @@ class CodeBackgroundSpan(
|
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
177
|
|
|
178
|
+
private fun leadingMarginAt(
|
|
179
|
+
text: Spanned,
|
|
180
|
+
lineStart: Int,
|
|
181
|
+
): Int {
|
|
182
|
+
if (lineStart >= text.length) return 0
|
|
183
|
+
val spans = text.getSpans(lineStart, lineStart + 1, LeadingMarginSpan::class.java)
|
|
184
|
+
var margin = 0
|
|
185
|
+
for (span in spans) {
|
|
186
|
+
margin += span.getLeadingMargin(false)
|
|
187
|
+
}
|
|
188
|
+
return margin
|
|
189
|
+
}
|
|
190
|
+
|
|
167
191
|
private fun adjustBottomForMargin(
|
|
168
192
|
text: Spanned,
|
|
169
193
|
lineEnd: Int,
|
|
@@ -12,27 +12,25 @@ import android.text.style.LeadingMarginSpan
|
|
|
12
12
|
import android.text.style.LineBackgroundSpan
|
|
13
13
|
import android.text.style.MetricAffectingSpan
|
|
14
14
|
import androidx.core.graphics.withSave
|
|
15
|
-
import com.swmansion.enriched.markdown.renderer.BlockStyle
|
|
16
15
|
import com.swmansion.enriched.markdown.renderer.SpanStyleCache
|
|
17
16
|
import com.swmansion.enriched.markdown.styles.CodeBlockStyle
|
|
18
|
-
import com.swmansion.enriched.markdown.utils.text.extensions.
|
|
17
|
+
import com.swmansion.enriched.markdown.utils.text.extensions.applyCodeBlockTextStyle
|
|
19
18
|
import com.swmansion.enriched.markdown.utils.text.extensions.applyColorPreserving
|
|
20
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Draws the commonmark-flavor code block box as per-line strips. The visual
|
|
22
|
+
* conventions (half-stroke border inset, radius reduced by that inset) must
|
|
23
|
+
* stay in sync with the whole-rect box the github flavor draws in
|
|
24
|
+
* CodeBlockContainerView.
|
|
25
|
+
*/
|
|
21
26
|
class CodeBlockSpan(
|
|
22
27
|
private val codeBlockStyle: CodeBlockStyle,
|
|
23
28
|
private val context: Context,
|
|
24
29
|
private val styleCache: SpanStyleCache,
|
|
30
|
+
private val leadingIndent: Int = 0,
|
|
25
31
|
) : MetricAffectingSpan(),
|
|
26
32
|
LineBackgroundSpan,
|
|
27
33
|
LeadingMarginSpan {
|
|
28
|
-
private val blockStyle =
|
|
29
|
-
BlockStyle(
|
|
30
|
-
fontSize = codeBlockStyle.fontSize,
|
|
31
|
-
fontFamily = codeBlockStyle.fontFamily,
|
|
32
|
-
fontWeight = codeBlockStyle.fontWeight,
|
|
33
|
-
color = codeBlockStyle.color,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
34
|
private val path = Path()
|
|
37
35
|
private val rect = RectF()
|
|
38
36
|
private val arcRect = RectF()
|
|
@@ -59,7 +57,7 @@ class CodeBlockSpan(
|
|
|
59
57
|
color = codeBlockStyle.borderColor
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
override fun getLeadingMargin(first: Boolean): Int = codeBlockStyle.padding.toInt()
|
|
60
|
+
override fun getLeadingMargin(first: Boolean): Int = codeBlockStyle.padding.toInt() + leadingIndent
|
|
63
61
|
|
|
64
62
|
override fun drawLeadingMargin(
|
|
65
63
|
c: Canvas?,
|
|
@@ -105,11 +103,12 @@ class CodeBlockSpan(
|
|
|
105
103
|
val inset = codeBlockStyle.borderWidth / 2f
|
|
106
104
|
|
|
107
105
|
rect.set(
|
|
108
|
-
left.toFloat() + inset,
|
|
106
|
+
left.toFloat() + leadingIndent + inset,
|
|
109
107
|
top.toFloat() + (if (isFirstLine) inset else 0f),
|
|
110
108
|
right.toFloat() - inset,
|
|
111
109
|
bottom.toFloat() - (if (isLastLine) inset else 0f),
|
|
112
110
|
)
|
|
111
|
+
if (rect.left >= rect.right) return
|
|
113
112
|
|
|
114
113
|
val radius = codeBlockStyle.borderRadius
|
|
115
114
|
val adjRadius = if (radius > inset) radius - inset else radius
|
|
@@ -187,10 +186,8 @@ class CodeBlockSpan(
|
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
private fun applyTextStyle(tp: TextPaint) {
|
|
190
|
-
tp.
|
|
191
|
-
|
|
192
|
-
tp.applyBlockStyleFont(blockStyle, context)
|
|
189
|
+
tp.applyCodeBlockTextStyle(codeBlockStyle, context)
|
|
193
190
|
|
|
194
|
-
tp.applyColorPreserving(
|
|
191
|
+
tp.applyColorPreserving(codeBlockStyle.color, *styleCache.colorsToPreserve)
|
|
195
192
|
}
|
|
196
193
|
}
|
|
@@ -24,7 +24,7 @@ class CodeSpan(
|
|
|
24
24
|
val preservedStyle = (paint.typeface?.style ?: 0) and (Typeface.BOLD or Typeface.ITALIC)
|
|
25
25
|
paint.typeface =
|
|
26
26
|
if (styleCache.codeFontFamily.isNotEmpty()) {
|
|
27
|
-
|
|
27
|
+
styleCache.getTypeface(styleCache.codeFontFamily, preservedStyle)
|
|
28
28
|
} else {
|
|
29
29
|
SpanStyleCache.getMonospaceTypeface(preservedStyle)
|
|
30
30
|
}
|
|
@@ -27,7 +27,7 @@ class EmphasisSpan(
|
|
|
27
27
|
tp.typeface =
|
|
28
28
|
if (styleCache.emphasisFontFamily.isNotEmpty()) {
|
|
29
29
|
val resolvedStyle = if (styleCache.emphasisFontStyle == "normal") Typeface.NORMAL else style
|
|
30
|
-
|
|
30
|
+
styleCache.getTypeface(styleCache.emphasisFontFamily, resolvedStyle)
|
|
31
31
|
} else if (styleCache.emphasisFontStyle == "normal") {
|
|
32
32
|
currentTypeface
|
|
33
33
|
} else {
|