@mathers101/react-native-render-rich-text 0.0.0-stage → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +140 -3
- package/ReactNativeRenderRichText.podspec +23 -0
- package/android/build.gradle +86 -0
- package/android/consumer-rules.pro +3 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/jni-adapter.cpp +191 -0
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapText.kt +673 -0
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -0
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextManager.kt +405 -0
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -0
- package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -0
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -0
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -0
- package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -0
- package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -0
- package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -0
- package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -0
- package/android/src/main/java/com/renderrichtext/events/FactoidPressEvent.kt +23 -0
- package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -0
- package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -0
- package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -0
- package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -0
- package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -0
- package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -0
- package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -0
- package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -0
- package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -0
- package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -0
- package/android/src/main/java/com/renderrichtext/parser/TiptapASTNode.kt +69 -0
- package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -0
- package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -0
- package/android/src/main/java/com/renderrichtext/renderer/BlockStyleContext.kt +181 -0
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -0
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -0
- package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -0
- package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -0
- package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -0
- package/android/src/main/java/com/renderrichtext/renderer/FactoidRenderer.kt +97 -0
- package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -0
- package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -0
- package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -0
- package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -0
- package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -0
- package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -0
- package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -0
- package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -0
- package/android/src/main/java/com/renderrichtext/renderer/NodeRenderer.kt +207 -0
- package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -0
- package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -0
- package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -0
- package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -0
- package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -0
- package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -0
- package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -0
- package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -0
- package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -0
- package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -0
- package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -0
- package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -0
- package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -0
- package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -0
- package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -0
- package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -0
- package/android/src/main/java/com/renderrichtext/spans/FactoidBackgroundSpan.kt +265 -0
- package/android/src/main/java/com/renderrichtext/spans/FactoidPaddingSpan.kt +258 -0
- package/android/src/main/java/com/renderrichtext/spans/FactoidSpan.kt +32 -0
- package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -0
- package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -0
- package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -0
- package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -0
- package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -0
- package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -0
- package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -0
- package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -0
- package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -0
- package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -0
- package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -0
- package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -0
- package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -0
- package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -0
- package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -0
- package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -0
- package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -0
- package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -0
- package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -0
- package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -0
- package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -0
- package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -0
- package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -0
- package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -0
- package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -0
- package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -0
- package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -0
- package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -0
- package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -0
- package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -0
- package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -0
- package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -0
- package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -0
- package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -0
- package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -0
- package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -0
- package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -0
- package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -0
- package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -0
- package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -0
- package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -0
- package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -0
- package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -0
- package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -0
- package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -0
- package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -0
- package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -0
- package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -0
- package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -0
- package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -0
- package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -0
- package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -0
- package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -0
- package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -0
- package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -0
- package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -0
- package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -0
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -0
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -0
- package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -0
- package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -0
- package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -0
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -0
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -0
- package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -0
- package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -0
- package/android/src/main/java/com/renderrichtext/utils/common/TiptapViewManagerUtils.kt +242 -0
- package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -0
- package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -0
- package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -0
- package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -0
- package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -0
- package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -0
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -0
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -0
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -0
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -0
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -0
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -0
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -0
- package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -0
- package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -0
- package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -0
- package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/LinkEvents.kt +88 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/LinkLongPressMovementMethod.kt +449 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -0
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -0
- package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -0
- package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -0
- package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -0
- package/android/src/main/jni/CMakeLists.txt +52 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -0
- package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -0
- package/cpp/parser/TiptapASTNode.hpp +68 -0
- package/cpp/parser/TiptapParser.cpp +233 -0
- package/cpp/parser/TiptapParser.hpp +13 -0
- package/cpp/vendor/nlohmann/json.hpp +24765 -0
- package/ios/EnrichedTiptapText.h +27 -0
- package/ios/EnrichedTiptapText.mm +1222 -0
- package/ios/attachments/ENRMImageAttachment.h +51 -0
- package/ios/attachments/ENRMImageAttachment.m +398 -0
- package/ios/attachments/ENRMLinkPillAttachment.h +47 -0
- package/ios/attachments/ENRMLinkPillAttachment.m +324 -0
- package/ios/attachments/ENRMLinkPillIconCache.h +28 -0
- package/ios/attachments/ENRMLinkPillIconCache.m +181 -0
- package/ios/attachments/ENRMLinkPillText.h +27 -0
- package/ios/attachments/ENRMLinkPillText.m +118 -0
- package/ios/attachments/ENRMMathInlineAttachment.h +7 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +4 -0
- package/ios/attachments/ThematicBreakAttachment.h +15 -0
- package/ios/attachments/ThematicBreakAttachment.m +33 -0
- package/ios/internals/ENRMViewFreeMeasurement.h +208 -0
- package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -0
- package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -0
- package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -0
- package/ios/internals/EnrichedTiptapTextState.h +24 -0
- package/ios/internals/MeasurementCache.h +308 -0
- package/ios/internals/ShadowMeasurementUtils.h +145 -0
- package/ios/parser/ENRMTextLinkAttributes.h +7 -0
- package/ios/parser/ENRMTiptapParser.h +33 -0
- package/ios/parser/ENRMTiptapParser.mm +73 -0
- package/ios/parser/TiptapASTNode.h +57 -0
- package/ios/parser/TiptapASTNode.m +52 -0
- package/ios/parser/TiptapParserBridge.mm +179 -0
- package/ios/renderer/AttributedRenderer.h +23 -0
- package/ios/renderer/AttributedRenderer.m +229 -0
- package/ios/renderer/BaseRenderer.h +33 -0
- package/ios/renderer/BaseRenderer.m +46 -0
- package/ios/renderer/BaselineShiftTextAttributes.h +10 -0
- package/ios/renderer/BaselineShiftTextAttributes.m +26 -0
- package/ios/renderer/BlankLineRenderer.h +4 -0
- package/ios/renderer/BlankLineRenderer.m +51 -0
- package/ios/renderer/BlockquoteRenderer.h +6 -0
- package/ios/renderer/BlockquoteRenderer.m +258 -0
- package/ios/renderer/CodeBlockRenderer.h +9 -0
- package/ios/renderer/CodeBlockRenderer.m +99 -0
- package/ios/renderer/CodeRenderer.h +9 -0
- package/ios/renderer/CodeRenderer.m +69 -0
- package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -0
- package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -0
- package/ios/renderer/EmphasisRenderer.h +5 -0
- package/ios/renderer/EmphasisRenderer.m +100 -0
- package/ios/renderer/FactoidRenderer.h +9 -0
- package/ios/renderer/FactoidRenderer.m +130 -0
- package/ios/renderer/HeadingRenderer.h +6 -0
- package/ios/renderer/HeadingRenderer.m +103 -0
- package/ios/renderer/HighlightRenderer.h +7 -0
- package/ios/renderer/HighlightRenderer.m +33 -0
- package/ios/renderer/LinkRenderer.h +6 -0
- package/ios/renderer/LinkRenderer.m +158 -0
- package/ios/renderer/ListItemRenderer.h +24 -0
- package/ios/renderer/ListItemRenderer.m +283 -0
- package/ios/renderer/ListRenderer.h +13 -0
- package/ios/renderer/ListRenderer.m +126 -0
- package/ios/renderer/MentionRenderer.h +9 -0
- package/ios/renderer/MentionRenderer.m +96 -0
- package/ios/renderer/NodeRenderer.h +8 -0
- package/ios/renderer/ParagraphRenderer.h +6 -0
- package/ios/renderer/ParagraphRenderer.m +85 -0
- package/ios/renderer/RenderContext.h +145 -0
- package/ios/renderer/RenderContext.m +403 -0
- package/ios/renderer/RendererFactory.h +12 -0
- package/ios/renderer/RendererFactory.m +158 -0
- package/ios/renderer/StrikethroughRenderer.h +5 -0
- package/ios/renderer/StrikethroughRenderer.m +30 -0
- package/ios/renderer/StrongRenderer.h +5 -0
- package/ios/renderer/StrongRenderer.m +88 -0
- package/ios/renderer/TextRenderer.h +6 -0
- package/ios/renderer/TextRenderer.m +18 -0
- package/ios/renderer/ThematicBreakRenderer.h +4 -0
- package/ios/renderer/ThematicBreakRenderer.m +42 -0
- package/ios/renderer/UnderlineRenderer.h +4 -0
- package/ios/renderer/UnderlineRenderer.m +41 -0
- package/ios/styles/ENRMFontSlot.h +12 -0
- package/ios/styles/ENRMFontSlot.m +24 -0
- package/ios/styles/StyleConfig.h +488 -0
- package/ios/styles/StyleConfig.mm +2820 -0
- package/ios/utils/AccessibilityInfo.h +35 -0
- package/ios/utils/AccessibilityInfo.m +24 -0
- package/ios/utils/BlockquoteBorder.h +26 -0
- package/ios/utils/BlockquoteBorder.m +294 -0
- package/ios/utils/CodeBackground.h +19 -0
- package/ios/utils/CodeBackground.m +197 -0
- package/ios/utils/CodeBlockBackground.h +17 -0
- package/ios/utils/CodeBlockBackground.m +103 -0
- package/ios/utils/ContextMenuUtils.h +76 -0
- package/ios/utils/ContextMenuUtils.mm +75 -0
- package/ios/utils/ENRMAccessibilityLabels.h +40 -0
- package/ios/utils/ENRMAccessibilityLabels.m +5 -0
- package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -0
- package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -0
- package/ios/utils/ENRMAtomicSize.h +65 -0
- package/ios/utils/ENRMCodeBlockContent.h +37 -0
- package/ios/utils/ENRMCodeBlockContent.mm +89 -0
- package/ios/utils/ENRMFeatureFlags.h +25 -0
- package/ios/utils/ENRMImageDownloader.h +30 -0
- package/ios/utils/ENRMImageDownloader.m +168 -0
- package/ios/utils/ENRMLatexErrorCoordinator.h +27 -0
- package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -0
- package/ios/utils/ENRMLatexErrorReporting.h +13 -0
- package/ios/utils/ENRMLinkContextMenus.h +93 -0
- package/ios/utils/ENRMLinkContextMenus.m +178 -0
- package/ios/utils/ENRMLinkRegexConfig.h +30 -0
- package/ios/utils/ENRMLinkRegexConfig.mm +104 -0
- package/ios/utils/ENRMLinkRegexProps.h +23 -0
- package/ios/utils/ENRMLocalImageLoader.h +35 -0
- package/ios/utils/ENRMLocalImageLoader.m +111 -0
- package/ios/utils/ENRMMenuAction.h +27 -0
- package/ios/utils/ENRMMenuAction.m +33 -0
- package/ios/utils/ENRMSpoilerOverlayManager.h +15 -0
- package/ios/utils/ENRMSpoilerOverlayManager.m +19 -0
- package/ios/utils/ENRMSpoilerTapUtils.h +6 -0
- package/ios/utils/ENRMSpoilerTapUtils.m +11 -0
- package/ios/utils/ENRMTailFadeInAnimator.h +16 -0
- package/ios/utils/ENRMTailFadeInAnimator.m +161 -0
- package/ios/utils/ENRMTextHitTest.h +23 -0
- package/ios/utils/ENRMTextHitTest.m +20 -0
- package/ios/utils/ENRMTextInteractionUtils.h +20 -0
- package/ios/utils/ENRMTextInteractionUtils.m +15 -0
- package/ios/utils/ENRMTextRenderer.h +38 -0
- package/ios/utils/ENRMTextRenderer.m +54 -0
- package/ios/utils/ENRMTextViewSetup.h +132 -0
- package/ios/utils/ENRMUIKit.h +429 -0
- package/ios/utils/EditMenuUtils.h +105 -0
- package/ios/utils/EditMenuUtils.m +143 -0
- package/ios/utils/FactoidBackground.h +20 -0
- package/ios/utils/FactoidBackground.m +161 -0
- package/ios/utils/FontScaleObserver.h +10 -0
- package/ios/utils/FontScaleObserver.m +55 -0
- package/ios/utils/FontUtils.h +31 -0
- package/ios/utils/FontUtils.m +63 -0
- package/ios/utils/HTMLGenerator.h +25 -0
- package/ios/utils/HTMLGenerator.m +1041 -0
- package/ios/utils/HeightUpdateUtils.h +25 -0
- package/ios/utils/ImageRequestHeaderUtils.h +35 -0
- package/ios/utils/LastElementUtils.h +97 -0
- package/ios/utils/LinkContextMenuUtils.h +55 -0
- package/ios/utils/LinkPillContentUtils.h +46 -0
- package/ios/utils/LinkTapUtils.h +56 -0
- package/ios/utils/LinkTapUtils.m +139 -0
- package/ios/utils/ListMarkerDrawer.h +15 -0
- package/ios/utils/ListMarkerDrawer.m +239 -0
- package/ios/utils/MentionBackground.h +26 -0
- package/ios/utils/MentionBackground.m +86 -0
- package/ios/utils/ParagraphStyleUtils.h +87 -0
- package/ios/utils/ParagraphStyleUtils.m +484 -0
- package/ios/utils/PasteboardUtils.h +48 -0
- package/ios/utils/PasteboardUtils.m +166 -0
- package/ios/utils/RTFExportUtils.h +24 -0
- package/ios/utils/RTFExportUtils.m +299 -0
- package/ios/utils/RuntimeKeys.h +44 -0
- package/ios/utils/RuntimeKeys.m +13 -0
- package/ios/utils/SelectionColorUtils.h +14 -0
- package/ios/utils/StylePropsUtils.h +1340 -0
- package/ios/utils/TaskListTapUtils.h +6 -0
- package/ios/utils/TaskListTapUtils.m +14 -0
- package/ios/utils/TextViewLayoutManager.h +14 -0
- package/ios/utils/TextViewLayoutManager.mm +198 -0
- package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -0
- package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -0
- package/ios/utils/TiptapExtractor.h +17 -0
- package/ios/utils/TiptapExtractor.m +367 -0
- package/ios/views/ENRMTiptapTextView.h +25 -0
- package/ios/views/ENRMTiptapTextView.m +247 -0
- package/package.json +70 -6
- package/react-native.config.js +10 -0
- package/src/EnrichedTiptapTextNativeComponent.ts +739 -0
- package/src/RichText.tsx +164 -0
- package/src/admonitionDefaults.ts +58 -0
- package/src/darkModeTextStyle.ts +99 -0
- package/src/headingDefaults.ts +21 -0
- package/src/index.tsx +4 -0
- package/src/linkVariantUtils.ts +120 -0
- package/src/normalizeTiptapStyle.ts +397 -0
- package/src/rn-globals.d.ts +1 -0
- package/src/styleUtils.ts +107 -0
- package/src/types/TiptapStyle.ts +532 -0
- package/src/types/TiptapStyleInternal.ts +299 -0
- package/src/types/linkPill.ts +9 -0
- package/src/utils/isDev.ts +4 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import com.renderrichtext.styles.BaseBlockStyle
|
|
4
|
+
import com.renderrichtext.styles.BlockquoteStyle
|
|
5
|
+
import com.renderrichtext.styles.CodeBlockStyle
|
|
6
|
+
import com.renderrichtext.styles.HeadingStyle
|
|
7
|
+
import com.renderrichtext.styles.ListStyle
|
|
8
|
+
import com.renderrichtext.styles.ParagraphStyle
|
|
9
|
+
|
|
10
|
+
enum class BlockType {
|
|
11
|
+
NONE,
|
|
12
|
+
PARAGRAPH,
|
|
13
|
+
HEADING,
|
|
14
|
+
BLOCKQUOTE,
|
|
15
|
+
UNORDERED_LIST,
|
|
16
|
+
ORDERED_LIST,
|
|
17
|
+
CODE_BLOCK,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
data class BlockStyle(
|
|
21
|
+
val fontSize: Float,
|
|
22
|
+
val fontFamily: String,
|
|
23
|
+
val fontWeight: String,
|
|
24
|
+
val color: Int,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
private data class BlockStyleEntry(
|
|
28
|
+
val blockType: BlockType,
|
|
29
|
+
val blockStyle: BlockStyle,
|
|
30
|
+
val headingLevel: Int,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
class BlockStyleContext {
|
|
34
|
+
var currentBlockType = BlockType.NONE
|
|
35
|
+
private set
|
|
36
|
+
|
|
37
|
+
private var currentHeadingLevel = 0
|
|
38
|
+
private val blockStyleStack = ArrayDeque<BlockStyleEntry>()
|
|
39
|
+
|
|
40
|
+
var blockquoteDepth = 0
|
|
41
|
+
var listDepth = 0
|
|
42
|
+
var listType: ListType? = null
|
|
43
|
+
var listItemNumber = 0
|
|
44
|
+
var listMarkerExtra = 0f
|
|
45
|
+
var ancestorMarkerOffset = 0f
|
|
46
|
+
var listItemMarkerExtra = 0f
|
|
47
|
+
var listItemMarkerWidth: Float? = null
|
|
48
|
+
var taskItemCount = 0
|
|
49
|
+
var accumulatedIndent = 0
|
|
50
|
+
|
|
51
|
+
val listItemStarts = mutableListOf<Int>()
|
|
52
|
+
|
|
53
|
+
private val orderedListItemNumbers = ArrayDeque<Int>()
|
|
54
|
+
|
|
55
|
+
enum class ListType { UNORDERED, ORDERED }
|
|
56
|
+
|
|
57
|
+
private fun pushBlockStyle(
|
|
58
|
+
type: BlockType,
|
|
59
|
+
style: BaseBlockStyle,
|
|
60
|
+
headingLevel: Int = 0,
|
|
61
|
+
) {
|
|
62
|
+
val entry =
|
|
63
|
+
BlockStyleEntry(
|
|
64
|
+
blockType = type,
|
|
65
|
+
blockStyle = BlockStyle(style.fontSize, style.fontFamily, style.fontWeight, style.color),
|
|
66
|
+
headingLevel = headingLevel,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
blockStyleStack.addLast(entry)
|
|
70
|
+
currentBlockType = type
|
|
71
|
+
currentHeadingLevel = headingLevel
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fun popBlockStyle() {
|
|
75
|
+
if (blockStyleStack.isNotEmpty()) {
|
|
76
|
+
blockStyleStack.removeLast()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
val parentStyle = blockStyleStack.lastOrNull()
|
|
80
|
+
if (parentStyle != null) {
|
|
81
|
+
currentBlockType = parentStyle.blockType
|
|
82
|
+
currentHeadingLevel = parentStyle.headingLevel
|
|
83
|
+
} else {
|
|
84
|
+
currentBlockType = BlockType.NONE
|
|
85
|
+
currentHeadingLevel = 0
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
fun setParagraphStyle(style: ParagraphStyle) = pushBlockStyle(BlockType.PARAGRAPH, style)
|
|
90
|
+
|
|
91
|
+
fun setHeadingStyle(
|
|
92
|
+
style: HeadingStyle,
|
|
93
|
+
level: Int,
|
|
94
|
+
) = pushBlockStyle(BlockType.HEADING, style, level)
|
|
95
|
+
|
|
96
|
+
fun setBlockquoteStyle(style: BlockquoteStyle) = pushBlockStyle(BlockType.BLOCKQUOTE, style)
|
|
97
|
+
|
|
98
|
+
fun setUnorderedListStyle(style: ListStyle) {
|
|
99
|
+
listType = ListType.UNORDERED
|
|
100
|
+
pushBlockStyle(BlockType.UNORDERED_LIST, style)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
fun setOrderedListStyle(style: ListStyle) {
|
|
104
|
+
listType = ListType.ORDERED
|
|
105
|
+
pushBlockStyle(BlockType.ORDERED_LIST, style)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fun setCodeBlockStyle(style: CodeBlockStyle) = pushBlockStyle(BlockType.CODE_BLOCK, style)
|
|
109
|
+
|
|
110
|
+
fun incrementListItemNumber() {
|
|
111
|
+
listItemNumber++
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
fun resetListItemNumber(startNumber: Int = 1) {
|
|
115
|
+
// ListItemRenderer pre-increments, so the counter starts one below the
|
|
116
|
+
// first rendered number.
|
|
117
|
+
listItemNumber = startNumber - 1
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun pushOrderedListItemNumber() {
|
|
121
|
+
orderedListItemNumbers.addLast(listItemNumber)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fun popOrderedListItemNumber() {
|
|
125
|
+
if (orderedListItemNumbers.isNotEmpty()) {
|
|
126
|
+
listItemNumber = orderedListItemNumbers.removeLast()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fun clearListStyle() {
|
|
131
|
+
popBlockStyle()
|
|
132
|
+
|
|
133
|
+
if (listDepth == 0) {
|
|
134
|
+
listType = null
|
|
135
|
+
listItemNumber = 0
|
|
136
|
+
orderedListItemNumbers.clear()
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Same font as the current block, with [color] as the base text color for nested inline nodes. */
|
|
141
|
+
fun pushInlineColor(color: Int) {
|
|
142
|
+
val current =
|
|
143
|
+
blockStyleStack.lastOrNull()
|
|
144
|
+
?: throw IllegalStateException(
|
|
145
|
+
"BlockStyle is null. Inline renderers must be used within a block context.",
|
|
146
|
+
)
|
|
147
|
+
blockStyleStack.addLast(current.copy(blockStyle = current.blockStyle.copy(color = color)))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fun popInlineColor() {
|
|
151
|
+
popBlockStyle()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fun requireBlockStyle(): BlockStyle {
|
|
155
|
+
val entry = blockStyleStack.lastOrNull()
|
|
156
|
+
return entry?.blockStyle
|
|
157
|
+
?: throw IllegalStateException(
|
|
158
|
+
"BlockStyle is null. Inline renderers must be used within a block context.",
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
fun currentBlockStyleOrNull(): BlockStyle? = blockStyleStack.lastOrNull()?.blockStyle
|
|
163
|
+
|
|
164
|
+
fun resetForNewRender() {
|
|
165
|
+
blockStyleStack.clear()
|
|
166
|
+
currentBlockType = BlockType.NONE
|
|
167
|
+
currentHeadingLevel = 0
|
|
168
|
+
blockquoteDepth = 0
|
|
169
|
+
listDepth = 0
|
|
170
|
+
listType = null
|
|
171
|
+
listItemNumber = 0
|
|
172
|
+
listMarkerExtra = 0f
|
|
173
|
+
ancestorMarkerOffset = 0f
|
|
174
|
+
listItemMarkerExtra = 0f
|
|
175
|
+
listItemMarkerWidth = null
|
|
176
|
+
taskItemCount = 0
|
|
177
|
+
accumulatedIndent = 0
|
|
178
|
+
listItemStarts.clear()
|
|
179
|
+
orderedListItemNumbers.clear()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import android.graphics.Paint
|
|
4
|
+
import android.text.SpannableStringBuilder
|
|
5
|
+
import android.text.Spanned
|
|
6
|
+
import android.text.style.LineHeightSpan
|
|
7
|
+
import com.renderrichtext.parser.TiptapASTNode
|
|
8
|
+
import com.renderrichtext.spans.BlockquoteSpan
|
|
9
|
+
import com.renderrichtext.spans.MarginBottomSpan
|
|
10
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
|
|
11
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE_PRIORITY
|
|
12
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_LINE_HEIGHT_PRIORITY
|
|
13
|
+
import com.renderrichtext.utils.text.span.applyLineHeightSkippingImages
|
|
14
|
+
import com.renderrichtext.utils.text.span.applyMarginBottom
|
|
15
|
+
import com.renderrichtext.utils.text.span.applyMarginTop
|
|
16
|
+
|
|
17
|
+
class BlockquoteRenderer(
|
|
18
|
+
private val config: RendererConfig,
|
|
19
|
+
) : NodeRenderer {
|
|
20
|
+
override fun render(
|
|
21
|
+
node: TiptapASTNode,
|
|
22
|
+
builder: SpannableStringBuilder,
|
|
23
|
+
onLinkPress: ((String) -> Unit)?,
|
|
24
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
25
|
+
onFactoidPress: ((String) -> Unit)?,
|
|
26
|
+
factory: RendererFactory,
|
|
27
|
+
) {
|
|
28
|
+
if (builder.isNotEmpty() && builder.last() != '\n') {
|
|
29
|
+
builder.append("\n")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
val start = builder.length
|
|
33
|
+
val style = config.style.blockquoteStyle
|
|
34
|
+
val context = factory.blockStyleContext
|
|
35
|
+
val depth = context.blockquoteDepth
|
|
36
|
+
|
|
37
|
+
// Track depth to handle nested indentation levels
|
|
38
|
+
context.blockquoteDepth = depth + 1
|
|
39
|
+
context.setBlockquoteStyle(style)
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress)
|
|
43
|
+
} finally {
|
|
44
|
+
context.popBlockStyle()
|
|
45
|
+
context.blockquoteDepth = depth
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (builder.length == start) return
|
|
49
|
+
// The last child's margin sits on its terminating newline, so the extra
|
|
50
|
+
// descent is part of the last content line and the quote background paints
|
|
51
|
+
// it. That reads as a large gap under the text. Lift it off the box.
|
|
52
|
+
var end = detachTrailingContentMargin(builder, start, depth)
|
|
53
|
+
if (end == start) return
|
|
54
|
+
if (depth == 0 && end == builder.length && builder[end - 1] != '\n') {
|
|
55
|
+
builder.append('\n')
|
|
56
|
+
end = builder.length
|
|
57
|
+
}
|
|
58
|
+
val padding = style.padding.toInt()
|
|
59
|
+
|
|
60
|
+
var contentStart = start
|
|
61
|
+
if (padding > 0) {
|
|
62
|
+
builder.insert(start, "\n")
|
|
63
|
+
factory.shiftDeferredSpans(start, 1)
|
|
64
|
+
builder.setSpan(
|
|
65
|
+
BlockquotePaddingSpacerSpan(padding),
|
|
66
|
+
start,
|
|
67
|
+
start + 1,
|
|
68
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
69
|
+
)
|
|
70
|
+
contentStart = start + 1
|
|
71
|
+
end += 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Find immediately nested quotes to exclude them from this level's line-height/margins
|
|
75
|
+
val nestedRanges =
|
|
76
|
+
builder
|
|
77
|
+
.getSpans(contentStart, end, BlockquoteSpan::class.java)
|
|
78
|
+
.filter { it.depth == depth + 1 }
|
|
79
|
+
.map { builder.getSpanStart(it) to builder.getSpanEnd(it) }
|
|
80
|
+
.sortedBy { it.first }
|
|
81
|
+
|
|
82
|
+
// The accent bar / background span covers the full box, incl. the top spacer.
|
|
83
|
+
// Top priority draws it first, so inline pill/chip backgrounds paint on top of its fill.
|
|
84
|
+
builder.setSpan(
|
|
85
|
+
BlockquoteSpan(style, depth, factory.context, factory.styleCache),
|
|
86
|
+
start,
|
|
87
|
+
end,
|
|
88
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE_PRIORITY,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
applyLineHeightExcludingNested(builder, nestedRanges, contentStart, end, style.lineHeight)
|
|
92
|
+
|
|
93
|
+
if (padding > 0) {
|
|
94
|
+
builder.setSpan(
|
|
95
|
+
BlockquoteBoundaryPaddingSpan(padding),
|
|
96
|
+
contentStart,
|
|
97
|
+
end,
|
|
98
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Margins are only applied by the outermost (root) quote
|
|
103
|
+
if (depth == 0) {
|
|
104
|
+
applyMarginTop(builder, start, style.marginTop)
|
|
105
|
+
applyMarginBottom(builder, style.marginBottom)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The last block inside the quote ends with a [MarginBottomSpan] on its
|
|
111
|
+
* terminating newline. That span adds its margin to the content line's descent,
|
|
112
|
+
* and the quote background fills the whole line, so the margin shows up as
|
|
113
|
+
* extra space under the text.
|
|
114
|
+
*
|
|
115
|
+
* A root quote drops that margin and keeps a bare newline, so the quote's own
|
|
116
|
+
* margin (applied after the box) is a separate spacer line outside the
|
|
117
|
+
* background. A nested quote keeps the margin, but on a following spacer line
|
|
118
|
+
* the box does not cover, so the parent still gets a gap before the next sibling.
|
|
119
|
+
*
|
|
120
|
+
* Returns the exclusive end index the quote box should use.
|
|
121
|
+
*/
|
|
122
|
+
private fun detachTrailingContentMargin(
|
|
123
|
+
builder: SpannableStringBuilder,
|
|
124
|
+
start: Int,
|
|
125
|
+
depth: Int,
|
|
126
|
+
): Int {
|
|
127
|
+
val end = builder.length
|
|
128
|
+
if (end <= start || builder[end - 1] != '\n') return end
|
|
129
|
+
|
|
130
|
+
val newline = end - 1
|
|
131
|
+
val marginSpans =
|
|
132
|
+
builder.getSpans(newline, end, MarginBottomSpan::class.java).filter {
|
|
133
|
+
builder.getSpanStart(it) == newline && builder.getSpanEnd(it) == end
|
|
134
|
+
}
|
|
135
|
+
if (marginSpans.isEmpty()) return end
|
|
136
|
+
|
|
137
|
+
val margin = marginSpans.maxOf { it.marginBottom }
|
|
138
|
+
val spacerLine = newline == start || builder[newline - 1] == '\n'
|
|
139
|
+
|
|
140
|
+
if (spacerLine) {
|
|
141
|
+
if (depth == 0) {
|
|
142
|
+
marginSpans.forEach { builder.removeSpan(it) }
|
|
143
|
+
builder.delete(newline, end)
|
|
144
|
+
return newline
|
|
145
|
+
}
|
|
146
|
+
return newline
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
marginSpans.forEach { builder.removeSpan(it) }
|
|
150
|
+
if (depth > 0 && margin > 0f) {
|
|
151
|
+
val spacer = builder.length
|
|
152
|
+
builder.append('\n')
|
|
153
|
+
builder.setSpan(
|
|
154
|
+
MarginBottomSpan(margin),
|
|
155
|
+
spacer,
|
|
156
|
+
builder.length,
|
|
157
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
158
|
+
)
|
|
159
|
+
return end
|
|
160
|
+
}
|
|
161
|
+
return builder.length
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A blockquote's top padding, rendered as a standalone spacer line of exactly
|
|
166
|
+
* [padding] px.
|
|
167
|
+
*
|
|
168
|
+
* Top padding cannot be added by growing the first content line's ascent:
|
|
169
|
+
* StaticLayout reuses one FontMetricsInt across a paragraph's soft-wrapped lines,
|
|
170
|
+
* so the inflated first-line metrics leak into the wrapped continuation line, where
|
|
171
|
+
* the line-height clamp then skews them into overlapping baselines. A spacer sits in
|
|
172
|
+
* its own paragraph, and setting absolute metrics keeps it fixed regardless of that
|
|
173
|
+
* reuse.
|
|
174
|
+
*/
|
|
175
|
+
private class BlockquotePaddingSpacerSpan(
|
|
176
|
+
private val padding: Int,
|
|
177
|
+
) : LineHeightSpan {
|
|
178
|
+
override fun chooseHeight(
|
|
179
|
+
text: CharSequence,
|
|
180
|
+
startLine: Int,
|
|
181
|
+
endLine: Int,
|
|
182
|
+
spanstartv: Int,
|
|
183
|
+
v: Int,
|
|
184
|
+
fm: Paint.FontMetricsInt,
|
|
185
|
+
) {
|
|
186
|
+
fm.top = 0
|
|
187
|
+
fm.ascent = 0
|
|
188
|
+
fm.descent = padding
|
|
189
|
+
fm.bottom = padding
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* A blockquote's bottom padding, grown onto the last content line's descent (safe
|
|
195
|
+
* because no later line inherits its metrics; top padding uses
|
|
196
|
+
* [BlockquotePaddingSpacerSpan]).
|
|
197
|
+
*
|
|
198
|
+
* The span range can include trailing '\n'(s) that form no visible line, so the last
|
|
199
|
+
* drawn line ends before getSpanEnd; the comparison uses the visible content end.
|
|
200
|
+
*/
|
|
201
|
+
private class BlockquoteBoundaryPaddingSpan(
|
|
202
|
+
private val padding: Int,
|
|
203
|
+
) : LineHeightSpan {
|
|
204
|
+
override fun chooseHeight(
|
|
205
|
+
text: CharSequence,
|
|
206
|
+
startLine: Int,
|
|
207
|
+
endLine: Int,
|
|
208
|
+
spanstartv: Int,
|
|
209
|
+
v: Int,
|
|
210
|
+
fm: Paint.FontMetricsInt,
|
|
211
|
+
) {
|
|
212
|
+
if (text !is Spanned) return
|
|
213
|
+
|
|
214
|
+
var contentEnd = text.getSpanEnd(this)
|
|
215
|
+
while (contentEnd > 0 && text[contentEnd - 1] == '\n') {
|
|
216
|
+
contentEnd--
|
|
217
|
+
}
|
|
218
|
+
if (endLine >= contentEnd) {
|
|
219
|
+
fm.descent += padding
|
|
220
|
+
fm.bottom += padding
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private fun applyLineHeightExcludingNested(
|
|
226
|
+
builder: SpannableStringBuilder,
|
|
227
|
+
nestedRanges: List<Pair<Int, Int>>,
|
|
228
|
+
start: Int,
|
|
229
|
+
end: Int,
|
|
230
|
+
lineHeight: Float,
|
|
231
|
+
) {
|
|
232
|
+
var currentPos = start
|
|
233
|
+
for ((nestedStart, nestedEnd) in nestedRanges) {
|
|
234
|
+
if (currentPos < nestedStart) {
|
|
235
|
+
applyLineHeightSkippingImages(builder, currentPos, nestedStart, lineHeight, SPAN_FLAGS_LINE_HEIGHT_PRIORITY)
|
|
236
|
+
}
|
|
237
|
+
currentPos = nestedEnd
|
|
238
|
+
}
|
|
239
|
+
if (currentPos < end) {
|
|
240
|
+
applyLineHeightSkippingImages(builder, currentPos, end, lineHeight, SPAN_FLAGS_LINE_HEIGHT_PRIORITY)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import com.renderrichtext.parser.TiptapASTNode
|
|
5
|
+
import com.renderrichtext.styles.BlockquoteStyle
|
|
6
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_LINE_HEIGHT_PRIORITY
|
|
7
|
+
import com.renderrichtext.utils.text.span.applyLineHeightSkippingImages
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Renders a GFM blockquote's own prose content - the nodes left after nested
|
|
11
|
+
* quotes, code blocks and other block segments have been split out - into a
|
|
12
|
+
* standalone buffer styled as blockquote text.
|
|
13
|
+
*
|
|
14
|
+
* It decorates a generic [Renderer.renderContent] pass rather than owning the
|
|
15
|
+
* render envelope itself: [push] enters the blockquote block style so text picks
|
|
16
|
+
* up the quote's font/color while still emitting block margins between children,
|
|
17
|
+
* matching the commonmark BlockquoteRenderer; [postProcess] applies the quote's
|
|
18
|
+
* line height once the builder is complete. It draws no border/background/padding
|
|
19
|
+
* - the BlockquoteContainerView draws the box.
|
|
20
|
+
*/
|
|
21
|
+
class BlockquoteTextRenderer(
|
|
22
|
+
private val style: BlockquoteStyle,
|
|
23
|
+
) {
|
|
24
|
+
fun render(
|
|
25
|
+
renderer: Renderer,
|
|
26
|
+
nodes: List<TiptapASTNode>,
|
|
27
|
+
onLinkPress: ((String) -> Unit)?,
|
|
28
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
29
|
+
onFactoidPress: ((String) -> Unit)?,
|
|
30
|
+
): SpannableStringBuilder = renderer.renderContent(nodes, onLinkPress, onLinkLongPress, onFactoidPress, block = this)
|
|
31
|
+
|
|
32
|
+
fun push(context: BlockStyleContext) {
|
|
33
|
+
context.blockquoteDepth += 1
|
|
34
|
+
context.setBlockquoteStyle(style)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fun pop(context: BlockStyleContext) {
|
|
38
|
+
context.popBlockStyle()
|
|
39
|
+
context.blockquoteDepth -= 1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fun postProcess(builder: SpannableStringBuilder) {
|
|
43
|
+
if (builder.isNotEmpty()) {
|
|
44
|
+
// Priority flag so this block-wide line height iterates before the per-block
|
|
45
|
+
// MarginBottomSpans, which then add their gap on top instead of being
|
|
46
|
+
// normalized away (see SPAN_FLAGS_LINE_HEIGHT_PRIORITY).
|
|
47
|
+
applyLineHeightSkippingImages(
|
|
48
|
+
builder,
|
|
49
|
+
0,
|
|
50
|
+
builder.length,
|
|
51
|
+
style.lineHeight,
|
|
52
|
+
SPAN_FLAGS_LINE_HEIGHT_PRIORITY,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import android.graphics.Paint
|
|
4
|
+
import android.text.SpannableStringBuilder
|
|
5
|
+
import android.text.Spanned
|
|
6
|
+
import android.text.style.LineHeightSpan
|
|
7
|
+
import com.renderrichtext.parser.TiptapASTNode
|
|
8
|
+
import com.renderrichtext.spans.CodeBlockSpan
|
|
9
|
+
import com.renderrichtext.spans.MarginBottomSpan
|
|
10
|
+
import com.renderrichtext.spans.isLastDrawnLine
|
|
11
|
+
import com.renderrichtext.utils.common.CodeBlockHighlighter
|
|
12
|
+
import com.renderrichtext.utils.common.CodeBlockNode
|
|
13
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
|
|
14
|
+
import com.renderrichtext.utils.text.span.applyMarginTop
|
|
15
|
+
|
|
16
|
+
class CodeBlockRenderer(
|
|
17
|
+
private val config: RendererConfig,
|
|
18
|
+
) : NodeRenderer {
|
|
19
|
+
override fun render(
|
|
20
|
+
node: TiptapASTNode,
|
|
21
|
+
builder: SpannableStringBuilder,
|
|
22
|
+
onLinkPress: ((String) -> Unit)?,
|
|
23
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
24
|
+
onFactoidPress: ((String) -> Unit)?,
|
|
25
|
+
factory: RendererFactory,
|
|
26
|
+
) {
|
|
27
|
+
if (builder.isNotEmpty() && builder.last() != '\n') {
|
|
28
|
+
builder.append("\n")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
val start = builder.length
|
|
32
|
+
val style = config.style.codeBlockStyle
|
|
33
|
+
val context = factory.blockStyleContext
|
|
34
|
+
|
|
35
|
+
applyMarginTop(builder, start, style.marginTop)
|
|
36
|
+
|
|
37
|
+
// Content starts after the potential 1-character marginTop spacer
|
|
38
|
+
val contentStart = start + (if (style.marginTop > 0) 1 else 0)
|
|
39
|
+
|
|
40
|
+
context.setCodeBlockStyle(style)
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress)
|
|
44
|
+
} finally {
|
|
45
|
+
context.popBlockStyle()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (builder.length == contentStart) return
|
|
49
|
+
|
|
50
|
+
CodeBlockHighlighter.highlight(
|
|
51
|
+
builder,
|
|
52
|
+
CodeBlockNode.extractCode(node),
|
|
53
|
+
CodeBlockNode.language(node),
|
|
54
|
+
style,
|
|
55
|
+
contentStart,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// Terminate the content so the margin newline below is its own line. Sharing
|
|
59
|
+
// the last code line makes that line's descent grow by marginBottom, and the
|
|
60
|
+
// background paints the whole line — the bottom edge is then the margin, and
|
|
61
|
+
// it is not recognized as the last line, so the bottom corners stay square.
|
|
62
|
+
if (builder.last() != '\n') {
|
|
63
|
+
builder.append('\n')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
val end = builder.length
|
|
67
|
+
val padding = style.padding.toInt()
|
|
68
|
+
|
|
69
|
+
// Apply background, borders, and horizontal padding to content only
|
|
70
|
+
builder.setSpan(
|
|
71
|
+
CodeBlockSpan(
|
|
72
|
+
style,
|
|
73
|
+
factory.context,
|
|
74
|
+
factory.styleCache,
|
|
75
|
+
context.accumulatedIndent,
|
|
76
|
+
CodeBlockNode.extractCode(node),
|
|
77
|
+
CodeBlockNode.language(node) ?: "",
|
|
78
|
+
),
|
|
79
|
+
contentStart,
|
|
80
|
+
end,
|
|
81
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
// Apply vertical padding via line height manipulation
|
|
85
|
+
builder.setSpan(
|
|
86
|
+
CodeBlockBoundaryPaddingSpan(padding),
|
|
87
|
+
contentStart,
|
|
88
|
+
end,
|
|
89
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
val marginStart = builder.length
|
|
93
|
+
builder.append("\n")
|
|
94
|
+
builder.setSpan(
|
|
95
|
+
MarginBottomSpan(style.marginBottom),
|
|
96
|
+
marginStart,
|
|
97
|
+
builder.length,
|
|
98
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Internal span to handle top/bottom padding by modifying font metrics.
|
|
104
|
+
*/
|
|
105
|
+
private class CodeBlockBoundaryPaddingSpan(
|
|
106
|
+
private val padding: Int,
|
|
107
|
+
) : LineHeightSpan {
|
|
108
|
+
override fun chooseHeight(
|
|
109
|
+
text: CharSequence,
|
|
110
|
+
startLine: Int,
|
|
111
|
+
endLine: Int,
|
|
112
|
+
spanstartv: Int,
|
|
113
|
+
v: Int,
|
|
114
|
+
fm: Paint.FontMetricsInt,
|
|
115
|
+
) {
|
|
116
|
+
if (text !is Spanned) return
|
|
117
|
+
|
|
118
|
+
val spanStart = text.getSpanStart(this)
|
|
119
|
+
val spanEnd = text.getSpanEnd(this)
|
|
120
|
+
|
|
121
|
+
// Adjust ascent/top for the first line to create internal top padding
|
|
122
|
+
if (startLine == spanStart) {
|
|
123
|
+
fm.ascent -= padding
|
|
124
|
+
fm.top -= padding
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Same last-line test as CodeBlockSpan, so the bottom padding lands on the
|
|
128
|
+
// line that draws the bottom corners.
|
|
129
|
+
if (isLastDrawnLine(text, endLine, spanEnd)) {
|
|
130
|
+
fm.descent += padding
|
|
131
|
+
fm.bottom += padding
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import com.renderrichtext.parser.TiptapASTNode
|
|
5
|
+
import com.renderrichtext.spans.CodeBackgroundSpan
|
|
6
|
+
import com.renderrichtext.spans.CodeSpan
|
|
7
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
|
|
8
|
+
|
|
9
|
+
class CodeRenderer(
|
|
10
|
+
private val config: RendererConfig,
|
|
11
|
+
) : NodeRenderer {
|
|
12
|
+
override fun render(
|
|
13
|
+
node: TiptapASTNode,
|
|
14
|
+
builder: SpannableStringBuilder,
|
|
15
|
+
onLinkPress: ((String) -> Unit)?,
|
|
16
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
17
|
+
onFactoidPress: ((String) -> Unit)?,
|
|
18
|
+
factory: RendererFactory,
|
|
19
|
+
) {
|
|
20
|
+
if (node.children.isEmpty() || node.children.all { it.content.isEmpty() }) return
|
|
21
|
+
|
|
22
|
+
factory.renderWithSpan(builder, { node.children.forEach { builder.append(it.content) } }) { start, end, blockStyle ->
|
|
23
|
+
builder.setSpan(
|
|
24
|
+
CodeSpan(factory.styleCache, blockStyle),
|
|
25
|
+
start,
|
|
26
|
+
end,
|
|
27
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
28
|
+
)
|
|
29
|
+
builder.setSpan(
|
|
30
|
+
CodeBackgroundSpan(config.style),
|
|
31
|
+
start,
|
|
32
|
+
end,
|
|
33
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.renderrichtext.renderer
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import com.renderrichtext.parser.TiptapASTNode
|
|
5
|
+
import com.renderrichtext.spans.EmphasisSpan
|
|
6
|
+
import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
|
|
7
|
+
|
|
8
|
+
class EmphasisRenderer(
|
|
9
|
+
private val config: RendererConfig,
|
|
10
|
+
) : NodeRenderer {
|
|
11
|
+
override fun render(
|
|
12
|
+
node: TiptapASTNode,
|
|
13
|
+
builder: SpannableStringBuilder,
|
|
14
|
+
onLinkPress: ((String) -> Unit)?,
|
|
15
|
+
onLinkLongPress: ((String) -> Unit)?,
|
|
16
|
+
onFactoidPress: ((String) -> Unit)?,
|
|
17
|
+
factory: RendererFactory,
|
|
18
|
+
) {
|
|
19
|
+
factory.renderWithSpan(builder, { factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress) }) { start, end, blockStyle ->
|
|
20
|
+
builder.setSpan(
|
|
21
|
+
EmphasisSpan(factory.styleCache, blockStyle),
|
|
22
|
+
start,
|
|
23
|
+
end,
|
|
24
|
+
SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|