@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,673 @@
|
|
|
1
|
+
package com.renderrichtext
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.res.Configuration
|
|
5
|
+
import android.graphics.Canvas
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.os.Handler
|
|
8
|
+
import android.os.Looper
|
|
9
|
+
import android.text.Layout
|
|
10
|
+
import android.util.AttributeSet
|
|
11
|
+
import android.util.Log
|
|
12
|
+
import android.util.TypedValue
|
|
13
|
+
import android.view.MotionEvent
|
|
14
|
+
import android.view.View
|
|
15
|
+
import android.view.View.MeasureSpec
|
|
16
|
+
import com.facebook.react.bridge.ReadableMap
|
|
17
|
+
import com.facebook.react.uimanager.BackgroundStyleApplicator
|
|
18
|
+
import com.facebook.react.uimanager.PixelUtil
|
|
19
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
20
|
+
import com.facebook.react.uimanager.style.LogicalEdge
|
|
21
|
+
import com.renderrichtext.accessibility.AccessibilityLabels
|
|
22
|
+
import com.renderrichtext.accessibility.AccessibleTiptapTextView
|
|
23
|
+
import com.renderrichtext.math.LatexErrorReporter
|
|
24
|
+
import com.renderrichtext.parser.Md4cFlags
|
|
25
|
+
import com.renderrichtext.parser.Parser
|
|
26
|
+
import com.renderrichtext.renderer.Renderer
|
|
27
|
+
import com.renderrichtext.spoiler.SpoilerCapable
|
|
28
|
+
import com.renderrichtext.spoiler.SpoilerOverlay
|
|
29
|
+
import com.renderrichtext.spoiler.SpoilerOverlayDrawer
|
|
30
|
+
import com.renderrichtext.styles.LinkPillContent
|
|
31
|
+
import com.renderrichtext.styles.StyleConfig
|
|
32
|
+
import com.renderrichtext.utils.common.BreakStrategyUtils
|
|
33
|
+
import com.renderrichtext.utils.common.EllipsizeUtils
|
|
34
|
+
import com.renderrichtext.utils.common.LinkRegexConfig
|
|
35
|
+
import com.renderrichtext.utils.common.emitCodeBlockPress
|
|
36
|
+
import com.renderrichtext.utils.text.TailFadeInAnimator
|
|
37
|
+
import com.renderrichtext.utils.text.interaction.CheckboxTouchHelper
|
|
38
|
+
import com.renderrichtext.utils.text.view.CodeBlockPressHost
|
|
39
|
+
import com.renderrichtext.utils.text.view.ImagePressHost
|
|
40
|
+
import com.renderrichtext.utils.text.view.LinkLongPressMovementMethod
|
|
41
|
+
import com.renderrichtext.utils.text.view.SelectionMenuConfig
|
|
42
|
+
import com.renderrichtext.utils.text.view.applySelectableState
|
|
43
|
+
import com.renderrichtext.utils.text.view.applySelectionColors
|
|
44
|
+
import com.renderrichtext.utils.text.view.cancelJSTouchForCheckboxTap
|
|
45
|
+
import com.renderrichtext.utils.text.view.cancelJSTouchForLinkTap
|
|
46
|
+
import com.renderrichtext.utils.text.view.createSelectionActionModeCallback
|
|
47
|
+
import com.renderrichtext.utils.text.view.emitFactoidPressEvent
|
|
48
|
+
import com.renderrichtext.utils.text.view.emitImagePressEvent
|
|
49
|
+
import com.renderrichtext.utils.text.view.emitLinkLongPressEvent
|
|
50
|
+
import com.renderrichtext.utils.text.view.emitLinkPressEvent
|
|
51
|
+
import com.renderrichtext.utils.text.view.emitMentionLongPressEvent
|
|
52
|
+
import com.renderrichtext.utils.text.view.emitMentionPressEvent
|
|
53
|
+
import com.renderrichtext.utils.text.view.setupAsTiptapTextView
|
|
54
|
+
import java.util.concurrent.Executors
|
|
55
|
+
import kotlin.math.ceil
|
|
56
|
+
import kotlin.math.roundToInt
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* EnrichedTiptapText that handles Tiptap parsing and rendering on a background thread.
|
|
60
|
+
* View starts invisible and becomes visible after render completes to avoid layout shift.
|
|
61
|
+
*/
|
|
62
|
+
class EnrichedTiptapText
|
|
63
|
+
@JvmOverloads
|
|
64
|
+
constructor(
|
|
65
|
+
context: Context,
|
|
66
|
+
attrs: AttributeSet? = null,
|
|
67
|
+
defStyleAttr: Int = 0,
|
|
68
|
+
) : AccessibleTiptapTextView(context, attrs, defStyleAttr),
|
|
69
|
+
SpoilerCapable,
|
|
70
|
+
ImagePressHost,
|
|
71
|
+
CodeBlockPressHost {
|
|
72
|
+
private val parser = Parser.shared
|
|
73
|
+
private val renderer = Renderer()
|
|
74
|
+
private var onLinkPressCallback: ((String) -> Unit)? = null
|
|
75
|
+
private var onLinkLongPressCallback: ((String) -> Unit)? = null
|
|
76
|
+
private var onFactoidPressCallback: ((String) -> Unit)? = null
|
|
77
|
+
private var onMentionPressCallback: ((String, String) -> Unit)? = null
|
|
78
|
+
private var onMentionLongPressCallback: ((String, String) -> Unit)? = null
|
|
79
|
+
private var onLatexErrorCallback: LatexErrorReporter? = null
|
|
80
|
+
|
|
81
|
+
private val reportedLatexErrors = HashSet<String>()
|
|
82
|
+
|
|
83
|
+
private val latexErrorReporter =
|
|
84
|
+
LatexErrorReporter { source, message, displayMode ->
|
|
85
|
+
val key = (if (displayMode) "B " else "I ") + source
|
|
86
|
+
if (reportedLatexErrors.add(key)) {
|
|
87
|
+
onLatexErrorCallback?.report(source, message, displayMode)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
private val checkboxTouchHelper = CheckboxTouchHelper(this)
|
|
91
|
+
|
|
92
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
93
|
+
private val executor = Executors.newSingleThreadExecutor()
|
|
94
|
+
private var currentRenderId = 0L
|
|
95
|
+
|
|
96
|
+
val layoutManager = EnrichedTiptapTextLayoutManager(this)
|
|
97
|
+
|
|
98
|
+
// used to force a Yoga re-measure when a block image resolves its box height
|
|
99
|
+
var stateWrapper: StateWrapper? = null
|
|
100
|
+
|
|
101
|
+
private var contextMenuItemTexts: List<String> = emptyList()
|
|
102
|
+
var onContextMenuItemPressCallback: ((itemText: String, selectedText: String, selectionStart: Int, selectionEnd: Int) -> Unit)? = null
|
|
103
|
+
|
|
104
|
+
var tiptapStyle: StyleConfig? = null
|
|
105
|
+
private set
|
|
106
|
+
|
|
107
|
+
var currentTiptap: String = ""
|
|
108
|
+
private set
|
|
109
|
+
|
|
110
|
+
var md4cFlags: Md4cFlags = Md4cFlags.DEFAULT
|
|
111
|
+
private set
|
|
112
|
+
private var linkRegex: LinkRegexConfig? = null
|
|
113
|
+
private var inlineCodeLinkRegex: LinkRegexConfig? = null
|
|
114
|
+
private var isGFM: Boolean = false
|
|
115
|
+
|
|
116
|
+
private var lastKnownFontScale: Float = context.resources.configuration.fontScale
|
|
117
|
+
private var tiptapStyleMap: ReadableMap? = null
|
|
118
|
+
|
|
119
|
+
private var allowFontScaling: Boolean = true
|
|
120
|
+
private var maxFontSizeMultiplier: Float = 0f
|
|
121
|
+
private var allowTrailingMargin: Boolean = false
|
|
122
|
+
private var imageRequestHeaders: Map<String, String> = emptyMap()
|
|
123
|
+
private var linkPillContent: Map<String, LinkPillContent> = emptyMap()
|
|
124
|
+
|
|
125
|
+
private var streamingAnimation: Boolean = false
|
|
126
|
+
private var previousTextLength: Int = 0
|
|
127
|
+
private var fadeAnimator: TailFadeInAnimator? = null
|
|
128
|
+
override var spoilerOverlayDrawer: SpoilerOverlayDrawer? = null
|
|
129
|
+
private set
|
|
130
|
+
var spoilerOverlay: SpoilerOverlay = SpoilerOverlay.PARTICLES
|
|
131
|
+
|
|
132
|
+
private var pendingStyledText: CharSequence? = null
|
|
133
|
+
|
|
134
|
+
private var mdNumberOfLines: Int = 0
|
|
135
|
+
private var mdEllipsizeMode: String = EllipsizeUtils.DEFAULT_MODE
|
|
136
|
+
private var mdSelectable: Boolean = true
|
|
137
|
+
|
|
138
|
+
private var selectionColor: Int? = null
|
|
139
|
+
private var selectionHandleColor: Int? = null
|
|
140
|
+
private var selectionMenuConfig = SelectionMenuConfig()
|
|
141
|
+
private var baseHorizontalPaddingLeft = 0
|
|
142
|
+
private var baseHorizontalPaddingRight = 0
|
|
143
|
+
private var applyingContentBoxInset = false
|
|
144
|
+
|
|
145
|
+
init {
|
|
146
|
+
setupAsTiptapTextView()
|
|
147
|
+
customSelectionActionModeCallback =
|
|
148
|
+
createSelectionActionModeCallback(
|
|
149
|
+
this,
|
|
150
|
+
getCustomItemTexts = { contextMenuItemTexts },
|
|
151
|
+
getSelectionMenuConfig = { selectionMenuConfig },
|
|
152
|
+
onCustomItemPress = { itemText, selectedText, start, end ->
|
|
153
|
+
onContextMenuItemPressCallback?.invoke(itemText, selectedText, start, end)
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
fun setTiptapContent(tiptap: String) {
|
|
159
|
+
if (currentTiptap == tiptap) return
|
|
160
|
+
currentTiptap = tiptap
|
|
161
|
+
scheduleRender()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
fun setTiptapStyle(style: ReadableMap?) {
|
|
165
|
+
tiptapStyleMap = style
|
|
166
|
+
// Register font scaling settings when style is set (view should have ID by now)
|
|
167
|
+
updateMeasurementStoreFontScaling()
|
|
168
|
+
val newStyle = style?.let { StyleConfig(it, context, allowFontScaling, maxFontSizeMultiplier) }
|
|
169
|
+
newStyle?.imageRequestHeaders = imageRequestHeaders
|
|
170
|
+
newStyle?.linkPillContent = linkPillContent
|
|
171
|
+
if (tiptapStyle == newStyle) return
|
|
172
|
+
tiptapStyle = newStyle
|
|
173
|
+
updateJustificationMode(newStyle)
|
|
174
|
+
scheduleRender()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
fun setImageRequestHeaders(headers: Map<String, String>) {
|
|
178
|
+
if (imageRequestHeaders == headers) return
|
|
179
|
+
imageRequestHeaders = headers
|
|
180
|
+
tiptapStyle?.imageRequestHeaders = headers
|
|
181
|
+
scheduleRenderIfNeeded()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
fun setLinkPillContent(content: Map<String, LinkPillContent>) {
|
|
185
|
+
if (linkPillContent == content) return
|
|
186
|
+
linkPillContent = content
|
|
187
|
+
tiptapStyle?.linkPillContent = content
|
|
188
|
+
scheduleRenderIfNeeded()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
192
|
+
super.onConfigurationChanged(newConfig)
|
|
193
|
+
|
|
194
|
+
if (!allowFontScaling) {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
val newFontScale = newConfig.fontScale
|
|
199
|
+
if (newFontScale != lastKnownFontScale) {
|
|
200
|
+
lastKnownFontScale = newFontScale
|
|
201
|
+
recreateStyleConfig()
|
|
202
|
+
scheduleRenderIfNeeded()
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fun setLinkRegex(config: LinkRegexConfig?) {
|
|
207
|
+
if (linkRegex == config) return
|
|
208
|
+
linkRegex = config
|
|
209
|
+
scheduleRenderIfNeeded()
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
fun setInlineCodeLinkRegex(config: LinkRegexConfig?) {
|
|
213
|
+
if (inlineCodeLinkRegex == config) return
|
|
214
|
+
inlineCodeLinkRegex = config
|
|
215
|
+
scheduleRenderIfNeeded()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fun setMd4cFlags(flags: Md4cFlags) {
|
|
219
|
+
if (md4cFlags == flags) return
|
|
220
|
+
md4cFlags = flags
|
|
221
|
+
scheduleRenderIfNeeded()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
fun setIsGFM(value: Boolean) {
|
|
225
|
+
if (isGFM == value) return
|
|
226
|
+
isGFM = value
|
|
227
|
+
scheduleRenderIfNeeded()
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
fun setAllowFontScaling(allow: Boolean) {
|
|
231
|
+
if (allowFontScaling == allow) return
|
|
232
|
+
allowFontScaling = allow
|
|
233
|
+
updateMeasurementStoreFontScaling()
|
|
234
|
+
recreateStyleConfig()
|
|
235
|
+
scheduleRenderIfNeeded()
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
fun setMaxFontSizeMultiplier(multiplier: Float) {
|
|
239
|
+
if (maxFontSizeMultiplier == multiplier) return
|
|
240
|
+
maxFontSizeMultiplier = multiplier
|
|
241
|
+
updateMeasurementStoreFontScaling()
|
|
242
|
+
recreateStyleConfig()
|
|
243
|
+
scheduleRenderIfNeeded()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fun setAllowTrailingMargin(allow: Boolean) {
|
|
247
|
+
if (allowTrailingMargin == allow) return
|
|
248
|
+
allowTrailingMargin = allow
|
|
249
|
+
scheduleRenderIfNeeded()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
fun setStreamingAnimation(enabled: Boolean) {
|
|
253
|
+
if (streamingAnimation == enabled) return
|
|
254
|
+
streamingAnimation = enabled
|
|
255
|
+
if (enabled) {
|
|
256
|
+
previousTextLength = text?.length ?: 0
|
|
257
|
+
} else {
|
|
258
|
+
fadeAnimator?.cancelAll()
|
|
259
|
+
fadeAnimator = null
|
|
260
|
+
previousTextLength = 0
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
fun commitProps() {
|
|
265
|
+
updateMeasurementStoreFontScaling()
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
private fun updateMeasurementStoreFontScaling() {
|
|
269
|
+
MeasurementStore.updateFontScalingSettings(id, allowFontScaling, maxFontSizeMultiplier)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private fun scheduleRenderIfNeeded() {
|
|
273
|
+
if (currentTiptap.isNotEmpty()) {
|
|
274
|
+
scheduleRender()
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private fun recreateStyleConfig() {
|
|
279
|
+
tiptapStyleMap?.let { styleMap ->
|
|
280
|
+
tiptapStyle =
|
|
281
|
+
StyleConfig(styleMap, context, allowFontScaling, maxFontSizeMultiplier).also {
|
|
282
|
+
it.imageRequestHeaders = imageRequestHeaders
|
|
283
|
+
it.linkPillContent = linkPillContent
|
|
284
|
+
}
|
|
285
|
+
updateJustificationMode(tiptapStyle)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private fun updateJustificationMode(style: StyleConfig?) {
|
|
290
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
291
|
+
justificationMode =
|
|
292
|
+
if (style?.needsJustify == true) {
|
|
293
|
+
Layout.JUSTIFICATION_MODE_INTER_WORD
|
|
294
|
+
} else {
|
|
295
|
+
Layout.JUSTIFICATION_MODE_NONE
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
private fun scheduleRender() {
|
|
301
|
+
val style = tiptapStyle ?: return
|
|
302
|
+
val tiptap = currentTiptap
|
|
303
|
+
if (tiptap.isEmpty()) return
|
|
304
|
+
|
|
305
|
+
val textLinkRegex = linkRegex
|
|
306
|
+
val codeLinkRegex = inlineCodeLinkRegex
|
|
307
|
+
val renderId = ++currentRenderId
|
|
308
|
+
|
|
309
|
+
executor.execute {
|
|
310
|
+
try {
|
|
311
|
+
val ast =
|
|
312
|
+
parser.parseTiptap(tiptap, md4cFlags, isGFM, textLinkRegex, codeLinkRegex) ?: run {
|
|
313
|
+
mainHandler.post { if (renderId == currentRenderId && isAttachedToWindow) text = "" }
|
|
314
|
+
return@execute
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
renderer.configure(style, context, latexErrorReporter)
|
|
318
|
+
val styledText =
|
|
319
|
+
renderer.renderDocument(
|
|
320
|
+
ast,
|
|
321
|
+
onLinkPressCallback,
|
|
322
|
+
onLinkLongPressCallback,
|
|
323
|
+
onFactoidPressCallback,
|
|
324
|
+
onMentionPressCallback,
|
|
325
|
+
onMentionLongPressCallback,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
mainHandler.post {
|
|
329
|
+
if (renderId == currentRenderId) {
|
|
330
|
+
if (isAttachedToWindow) {
|
|
331
|
+
applyRenderedText(styledText)
|
|
332
|
+
} else {
|
|
333
|
+
pendingStyledText = styledText
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} catch (e: Exception) {
|
|
338
|
+
Log.e(TAG, "Render failed: ${e.message}", e)
|
|
339
|
+
mainHandler.post { if (renderId == currentRenderId && isAttachedToWindow) text = "" }
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private fun applyRenderedText(styledText: CharSequence) {
|
|
345
|
+
val tailStart = previousTextLength
|
|
346
|
+
|
|
347
|
+
tiptapStyle?.paragraphStyle?.fontSize?.let {
|
|
348
|
+
setTextSize(TypedValue.COMPLEX_UNIT_PX, it)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
text = styledText
|
|
352
|
+
|
|
353
|
+
applyInteractivity()
|
|
354
|
+
|
|
355
|
+
renderer.getCollectedImageSpans().forEach { span ->
|
|
356
|
+
span.registerTextView(this)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
spoilerOverlayDrawer = SpoilerOverlayDrawer.setupIfNeeded(this, styledText, spoilerOverlayDrawer, spoilerOverlay)
|
|
360
|
+
|
|
361
|
+
layoutManager.invalidateLayout()
|
|
362
|
+
accessibilityHelper.invalidateAccessibilityItems()
|
|
363
|
+
|
|
364
|
+
if (streamingAnimation) {
|
|
365
|
+
if (fadeAnimator == null) {
|
|
366
|
+
fadeAnimator = TailFadeInAnimator(this)
|
|
367
|
+
}
|
|
368
|
+
fadeAnimator?.animate(tailStart, styledText.length)
|
|
369
|
+
previousTextLength = styledText.length
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
applySelectionColors(selectionColor, selectionHandleColor)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Trailing bottom margin included in the shadow-node measurement — must be
|
|
376
|
+
// mirrored when re-storing the measurement from the display text.
|
|
377
|
+
fun trailingMarginBottomPx(): Float = if (allowTrailingMargin) renderer.getLastElementMarginBottom() else 0f
|
|
378
|
+
|
|
379
|
+
fun setContextMenuItems(items: List<String>) {
|
|
380
|
+
contextMenuItemTexts = items
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
fun setSelectionMenuConfig(config: SelectionMenuConfig) {
|
|
384
|
+
if (selectionMenuConfig == config) return
|
|
385
|
+
selectionMenuConfig = config
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
fun setAccessibilityLabels(labels: AccessibilityLabels) {
|
|
389
|
+
accessibilityHelper.labels = labels
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
fun setIsSelectable(selectable: Boolean) {
|
|
393
|
+
mdSelectable = selectable
|
|
394
|
+
applyInteractivity()
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
fun setSelectionColor(color: Int?) {
|
|
398
|
+
if (selectionColor == color) return
|
|
399
|
+
selectionColor = color
|
|
400
|
+
applySelectionColors(selectionColor, selectionHandleColor)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
fun setSelectionHandleColor(color: Int?) {
|
|
404
|
+
if (selectionHandleColor == color) return
|
|
405
|
+
selectionHandleColor = color
|
|
406
|
+
applySelectionColors(selectionColor, selectionHandleColor)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
fun setTextBreakStrategy(strategy: String) {
|
|
410
|
+
MeasurementStore.updateBreakStrategy(id, strategy)
|
|
411
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
412
|
+
breakStrategy = BreakStrategyUtils.resolveBreakStrategy(strategy)
|
|
413
|
+
}
|
|
414
|
+
MeasurementStore.invalidate(id)
|
|
415
|
+
scheduleRenderIfNeeded()
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
fun setTiptapNumberOfLines(value: Int) {
|
|
419
|
+
val normalized = value.coerceAtLeast(0)
|
|
420
|
+
if (mdNumberOfLines == normalized) return
|
|
421
|
+
mdNumberOfLines = normalized
|
|
422
|
+
MeasurementStore.updateNumberOfLines(id, normalized)
|
|
423
|
+
applyLineLimitToView()
|
|
424
|
+
MeasurementStore.invalidate(id)
|
|
425
|
+
scheduleRenderIfNeeded()
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fun setTiptapEllipsizeMode(value: String) {
|
|
429
|
+
if (mdEllipsizeMode == value) return
|
|
430
|
+
mdEllipsizeMode = value
|
|
431
|
+
MeasurementStore.updateEllipsizeMode(id, value)
|
|
432
|
+
applyLineLimitToView()
|
|
433
|
+
MeasurementStore.invalidate(id)
|
|
434
|
+
scheduleRenderIfNeeded()
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Mirrors RN's ReactTextView.updateView: only ellipsize when a line limit is
|
|
438
|
+
// set; unlimited restores the default unbounded, non-ellipsized state.
|
|
439
|
+
private fun applyLineLimitToView() {
|
|
440
|
+
if (mdNumberOfLines > 0) {
|
|
441
|
+
maxLines = mdNumberOfLines
|
|
442
|
+
ellipsize = EllipsizeUtils.resolveTruncateAt(mdEllipsizeMode)
|
|
443
|
+
} else {
|
|
444
|
+
maxLines = Integer.MAX_VALUE
|
|
445
|
+
ellipsize = null
|
|
446
|
+
}
|
|
447
|
+
applyInteractivity()
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// The numberOfLines ellipsis and text selection / link taps are mutually
|
|
451
|
+
// exclusive on Android and cannot be reconciled. Both setTextIsSelectable(true)
|
|
452
|
+
// and a non-null movementMethod force the display text to a Spannable, which
|
|
453
|
+
// makes TextView pick DynamicLayout (TextView.useDynamicLayout). DynamicLayout
|
|
454
|
+
// has no setMaxLines, so the clamp is never baked into the layout and no
|
|
455
|
+
// ellipsis glyph is drawn (verified against AOSP TextView/DynamicLayout on
|
|
456
|
+
// API 35/36). To keep the ellipsis, a clamped view must be non-selectable AND
|
|
457
|
+
// drop its movement method; both are restored to the user's preference once
|
|
458
|
+
// the clamp is removed.
|
|
459
|
+
private fun applyInteractivity() {
|
|
460
|
+
if (mdNumberOfLines > 0) {
|
|
461
|
+
if (isTextSelectable) setTextIsSelectable(false)
|
|
462
|
+
movementMethod = null
|
|
463
|
+
} else {
|
|
464
|
+
applySelectableState(mdSelectable)
|
|
465
|
+
if (movementMethod !is LinkLongPressMovementMethod) {
|
|
466
|
+
movementMethod = LinkLongPressMovementMethod.createInstance()
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
fun emitOnLinkPress(url: String) {
|
|
472
|
+
emitLinkPressEvent(url)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
fun emitOnFactoidPress(factoidId: String) {
|
|
476
|
+
emitFactoidPressEvent(factoidId)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
fun emitOnMentionPress(
|
|
480
|
+
mentionId: String,
|
|
481
|
+
label: String,
|
|
482
|
+
) {
|
|
483
|
+
emitMentionPressEvent(mentionId, label)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
fun emitOnMentionLongPress(
|
|
487
|
+
mentionId: String,
|
|
488
|
+
label: String,
|
|
489
|
+
) {
|
|
490
|
+
emitMentionLongPressEvent(mentionId, label)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
fun emitOnLinkLongPress(url: String) {
|
|
494
|
+
emitLinkLongPressEvent(url)
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
override var imagePressEnabled: Boolean = false
|
|
498
|
+
private set
|
|
499
|
+
|
|
500
|
+
override fun emitOnImagePress(
|
|
501
|
+
url: String,
|
|
502
|
+
altText: String,
|
|
503
|
+
) {
|
|
504
|
+
emitImagePressEvent(url, altText)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
fun setEnableImagePress(enabled: Boolean) {
|
|
508
|
+
imagePressEnabled = enabled
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
override var codeBlockPressEnabled: Boolean = false
|
|
512
|
+
private set
|
|
513
|
+
|
|
514
|
+
override fun emitOnCodeBlockPress(
|
|
515
|
+
code: String,
|
|
516
|
+
language: String,
|
|
517
|
+
) {
|
|
518
|
+
emitCodeBlockPress(this, code, language)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
fun setEnableCodeBlockPress(enabled: Boolean) {
|
|
522
|
+
codeBlockPressEnabled = enabled
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
fun setOnLinkPressCallback(callback: (String) -> Unit) {
|
|
526
|
+
onLinkPressCallback = callback
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
fun setOnFactoidPressCallback(callback: (String) -> Unit) {
|
|
530
|
+
onFactoidPressCallback = callback
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
fun setOnMentionPressCallback(callback: (String, String) -> Unit) {
|
|
534
|
+
onMentionPressCallback = callback
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
fun setOnMentionLongPressCallback(callback: (String, String) -> Unit) {
|
|
538
|
+
onMentionLongPressCallback = callback
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
fun setOnLinkLongPressCallback(callback: (String) -> Unit) {
|
|
542
|
+
onLinkLongPressCallback = callback
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
fun setOnLatexErrorCallback(callback: LatexErrorReporter) {
|
|
546
|
+
onLatexErrorCallback = callback
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
fun setOnTaskListItemPressCallback(callback: ((taskIndex: Int, checked: Boolean, itemText: String) -> Unit)?) {
|
|
550
|
+
checkboxTouchHelper.onCheckboxTap = callback
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
fun setEnableTaskListItemToggle(enabled: Boolean) {
|
|
554
|
+
checkboxTouchHelper.isEnabled = enabled
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
fun cleanup() {
|
|
558
|
+
currentRenderId++
|
|
559
|
+
executor.shutdownNow()
|
|
560
|
+
mainHandler.removeCallbacksAndMessages(null)
|
|
561
|
+
pendingStyledText = null
|
|
562
|
+
fadeAnimator?.cancelAll()
|
|
563
|
+
fadeAnimator = null
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
override fun setPadding(
|
|
567
|
+
left: Int,
|
|
568
|
+
top: Int,
|
|
569
|
+
right: Int,
|
|
570
|
+
bottom: Int,
|
|
571
|
+
) {
|
|
572
|
+
if (!applyingContentBoxInset) {
|
|
573
|
+
baseHorizontalPaddingLeft = left
|
|
574
|
+
baseHorizontalPaddingRight = right
|
|
575
|
+
}
|
|
576
|
+
super.setPadding(left, top, right, bottom)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
override fun onMeasure(
|
|
580
|
+
widthMeasureSpec: Int,
|
|
581
|
+
heightMeasureSpec: Int,
|
|
582
|
+
) {
|
|
583
|
+
applyContentBoxInset(widthMeasureSpec)
|
|
584
|
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Fabric measures text at the content box (frame - padding - border) but the TextView's
|
|
589
|
+
* padding carries no border, so it wraps ~1dp wider and reserves a phantom trailing line
|
|
590
|
+
* under an unclamped box (#805). Fold the border into padding to match; restore the base
|
|
591
|
+
* padding when the cache or an exact frame is missing so no stale inset lingers.
|
|
592
|
+
*/
|
|
593
|
+
private fun applyContentBoxInset(widthMeasureSpec: Int) {
|
|
594
|
+
val contentBox =
|
|
595
|
+
if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
|
|
596
|
+
MeasurementStore.contentBoxWidthPx(id)?.let { ceil(it).toInt() }?.takeIf { it > 0 }
|
|
597
|
+
} else {
|
|
598
|
+
null
|
|
599
|
+
}
|
|
600
|
+
val frame = MeasureSpec.getSize(widthMeasureSpec)
|
|
601
|
+
if (contentBox == null || frame <= 0) {
|
|
602
|
+
setHorizontalPadding(baseHorizontalPaddingLeft, baseHorizontalPaddingRight)
|
|
603
|
+
return
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
val totalInset = (frame - contentBox).coerceIn(0, frame)
|
|
607
|
+
val left = (baseHorizontalPaddingLeft + resolvedBorderPx(leftEdge = true)).coerceIn(0, totalInset)
|
|
608
|
+
val right = (totalInset - left).coerceAtLeast(0)
|
|
609
|
+
setHorizontalPadding(left, right)
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Physical border width (px); only the left/right split reads it, never the total inset.
|
|
613
|
+
private fun resolvedBorderPx(leftEdge: Boolean): Int {
|
|
614
|
+
val rtl = layoutDirection == View.LAYOUT_DIRECTION_RTL
|
|
615
|
+
val physical = if (leftEdge) LogicalEdge.LEFT else LogicalEdge.RIGHT
|
|
616
|
+
val logical = if (leftEdge != rtl) LogicalEdge.START else LogicalEdge.END
|
|
617
|
+
val dp =
|
|
618
|
+
BackgroundStyleApplicator.getBorderWidth(this, physical)
|
|
619
|
+
?: BackgroundStyleApplicator.getBorderWidth(this, logical)
|
|
620
|
+
?: BackgroundStyleApplicator.getBorderWidth(this, LogicalEdge.ALL)
|
|
621
|
+
?: return 0
|
|
622
|
+
return PixelUtil.toPixelFromDIP(dp).roundToInt().coerceAtLeast(0)
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
private fun setHorizontalPadding(
|
|
626
|
+
left: Int,
|
|
627
|
+
right: Int,
|
|
628
|
+
) {
|
|
629
|
+
if (left == paddingLeft && right == paddingRight) return
|
|
630
|
+
applyingContentBoxInset = true
|
|
631
|
+
super.setPadding(left, paddingTop, right, paddingBottom)
|
|
632
|
+
applyingContentBoxInset = false
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
override fun onAttachedToWindow() {
|
|
636
|
+
super.onAttachedToWindow()
|
|
637
|
+
pendingStyledText?.let {
|
|
638
|
+
pendingStyledText = null
|
|
639
|
+
applyRenderedText(it)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
override fun onDetachedFromWindow() {
|
|
644
|
+
stopSpoilerAnimations()
|
|
645
|
+
super.onDetachedFromWindow()
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
override fun onDraw(canvas: Canvas) {
|
|
649
|
+
super.onDraw(canvas)
|
|
650
|
+
spoilerOverlayDrawer?.draw(canvas)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
private fun stopSpoilerAnimations() {
|
|
654
|
+
spoilerOverlayDrawer?.stop()
|
|
655
|
+
spoilerOverlayDrawer = null
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
659
|
+
if (checkboxTouchHelper.onTouchEvent(event)) {
|
|
660
|
+
if (event.action == MotionEvent.ACTION_DOWN) {
|
|
661
|
+
cancelJSTouchForCheckboxTap(event)
|
|
662
|
+
}
|
|
663
|
+
return true
|
|
664
|
+
}
|
|
665
|
+
val result = super.onTouchEvent(event)
|
|
666
|
+
if (event.action == MotionEvent.ACTION_DOWN) cancelJSTouchForLinkTap(event)
|
|
667
|
+
return result
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
companion object {
|
|
671
|
+
private const val TAG = "EnrichedTiptapMeasure"
|
|
672
|
+
}
|
|
673
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package com.renderrichtext
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
|
|
5
|
+
class EnrichedTiptapTextLayoutManager(
|
|
6
|
+
private val view: EnrichedTiptapText,
|
|
7
|
+
) {
|
|
8
|
+
private var forceHeightRecalculationCounter = 0
|
|
9
|
+
|
|
10
|
+
fun invalidateLayout() {
|
|
11
|
+
val text = view.text
|
|
12
|
+
val paint = view.paint
|
|
13
|
+
val heightChanged = MeasurementStore.store(view.id, text, paint, view.trailingMarginBottomPx())
|
|
14
|
+
if (!heightChanged) return
|
|
15
|
+
val stateWrapper = view.stateWrapper ?: return
|
|
16
|
+
val state = Arguments.createMap()
|
|
17
|
+
state.putInt("forceHeightRecalculationCounter", ++forceHeightRecalculationCounter)
|
|
18
|
+
stateWrapper.updateState(state)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fun releaseMeasurementStore() {
|
|
22
|
+
MeasurementStore.release(view.id)
|
|
23
|
+
}
|
|
24
|
+
}
|