@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,308 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <CoreGraphics/CGBase.h>
|
|
4
|
+
#include <React/RCTUtils.h>
|
|
5
|
+
#include <list>
|
|
6
|
+
#include <mutex>
|
|
7
|
+
#include <react/renderer/graphics/Float.h>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <tuple>
|
|
10
|
+
#include <unordered_map>
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
struct HashUtils {
|
|
15
|
+
|
|
16
|
+
static inline size_t combine(size_t h, size_t v)
|
|
17
|
+
{
|
|
18
|
+
return h ^ (v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
template <typename T> static inline void hash_one(size_t &seed, const T &v)
|
|
22
|
+
{
|
|
23
|
+
seed = combine(seed, std::hash<T>{}(v));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
enum class TiptapFlavor : uint8_t {
|
|
28
|
+
CommonMark = 0,
|
|
29
|
+
GitHub = 1,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
struct MeasurementCacheKey {
|
|
33
|
+
std::string tiptap;
|
|
34
|
+
CGFloat maxWidth;
|
|
35
|
+
bool allowTrailingMargin;
|
|
36
|
+
bool allowFontScaling;
|
|
37
|
+
double maxFontSizeMultiplier;
|
|
38
|
+
bool md4cFlagsUnderline;
|
|
39
|
+
bool md4cFlagsSuperscript;
|
|
40
|
+
bool md4cFlagsSubscript;
|
|
41
|
+
bool md4cFlagsHighlight;
|
|
42
|
+
bool md4cFlagsLatexMath;
|
|
43
|
+
bool md4cFlagsHardSoftBreaks;
|
|
44
|
+
bool md4cFlagsPreserveBlankLines;
|
|
45
|
+
bool md4cFlagsAdmonitions;
|
|
46
|
+
size_t styleFingerprint;
|
|
47
|
+
size_t linkPillContentFingerprint;
|
|
48
|
+
// Code blocks the user wrapped (view state, not props); 0 when none.
|
|
49
|
+
size_t wrappedCodeBlocksFingerprint;
|
|
50
|
+
CGFloat fontScale;
|
|
51
|
+
TiptapFlavor flavor;
|
|
52
|
+
std::string lineBreakStrategyIOS;
|
|
53
|
+
std::string writingDirection;
|
|
54
|
+
int numberOfLines;
|
|
55
|
+
std::string ellipsizeMode;
|
|
56
|
+
std::string linkRegexKey;
|
|
57
|
+
std::string inlineCodeLinkRegexKey;
|
|
58
|
+
|
|
59
|
+
bool operator==(const MeasurementCacheKey &other) const
|
|
60
|
+
{
|
|
61
|
+
return std::tie(tiptap, maxWidth, allowTrailingMargin, allowFontScaling, maxFontSizeMultiplier,
|
|
62
|
+
md4cFlagsUnderline, md4cFlagsSuperscript, md4cFlagsSubscript, md4cFlagsHighlight,
|
|
63
|
+
md4cFlagsLatexMath, md4cFlagsHardSoftBreaks, md4cFlagsPreserveBlankLines, md4cFlagsAdmonitions,
|
|
64
|
+
styleFingerprint, linkPillContentFingerprint, wrappedCodeBlocksFingerprint, fontScale, flavor,
|
|
65
|
+
lineBreakStrategyIOS, writingDirection, numberOfLines, ellipsizeMode, linkRegexKey,
|
|
66
|
+
inlineCodeLinkRegexKey) ==
|
|
67
|
+
std::tie(other.tiptap, other.maxWidth, other.allowTrailingMargin, other.allowFontScaling,
|
|
68
|
+
other.maxFontSizeMultiplier, other.md4cFlagsUnderline, other.md4cFlagsSuperscript,
|
|
69
|
+
other.md4cFlagsSubscript, other.md4cFlagsHighlight, other.md4cFlagsLatexMath,
|
|
70
|
+
other.md4cFlagsHardSoftBreaks, other.md4cFlagsPreserveBlankLines, other.md4cFlagsAdmonitions,
|
|
71
|
+
other.styleFingerprint, other.linkPillContentFingerprint, other.wrappedCodeBlocksFingerprint,
|
|
72
|
+
other.fontScale, other.flavor, other.lineBreakStrategyIOS, other.writingDirection,
|
|
73
|
+
other.numberOfLines, other.ellipsizeMode, other.linkRegexKey, other.inlineCodeLinkRegexKey);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
struct MeasurementCacheKeyHash {
|
|
78
|
+
size_t operator()(const MeasurementCacheKey &key) const
|
|
79
|
+
{
|
|
80
|
+
size_t h = 0;
|
|
81
|
+
HashUtils::hash_one(h, key.tiptap);
|
|
82
|
+
HashUtils::hash_one(h, key.maxWidth);
|
|
83
|
+
HashUtils::hash_one(h, key.allowTrailingMargin);
|
|
84
|
+
HashUtils::hash_one(h, key.allowFontScaling);
|
|
85
|
+
HashUtils::hash_one(h, key.maxFontSizeMultiplier);
|
|
86
|
+
HashUtils::hash_one(h, key.md4cFlagsUnderline);
|
|
87
|
+
HashUtils::hash_one(h, key.md4cFlagsSuperscript);
|
|
88
|
+
HashUtils::hash_one(h, key.md4cFlagsSubscript);
|
|
89
|
+
HashUtils::hash_one(h, key.md4cFlagsHighlight);
|
|
90
|
+
HashUtils::hash_one(h, key.md4cFlagsLatexMath);
|
|
91
|
+
HashUtils::hash_one(h, key.md4cFlagsHardSoftBreaks);
|
|
92
|
+
HashUtils::hash_one(h, key.md4cFlagsPreserveBlankLines);
|
|
93
|
+
HashUtils::hash_one(h, key.md4cFlagsAdmonitions);
|
|
94
|
+
HashUtils::hash_one(h, key.styleFingerprint);
|
|
95
|
+
HashUtils::hash_one(h, key.linkPillContentFingerprint);
|
|
96
|
+
HashUtils::hash_one(h, key.wrappedCodeBlocksFingerprint);
|
|
97
|
+
HashUtils::hash_one(h, key.fontScale);
|
|
98
|
+
HashUtils::hash_one(h, static_cast<uint8_t>(key.flavor));
|
|
99
|
+
HashUtils::hash_one(h, key.lineBreakStrategyIOS);
|
|
100
|
+
HashUtils::hash_one(h, key.writingDirection);
|
|
101
|
+
HashUtils::hash_one(h, key.numberOfLines);
|
|
102
|
+
HashUtils::hash_one(h, key.ellipsizeMode);
|
|
103
|
+
HashUtils::hash_one(h, key.linkRegexKey);
|
|
104
|
+
HashUtils::hash_one(h, key.inlineCodeLinkRegexKey);
|
|
105
|
+
return h;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
struct CachedSize {
|
|
110
|
+
CGFloat width;
|
|
111
|
+
CGFloat height;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
template <typename StyleStruct> inline size_t computeStyleFingerprint(const StyleStruct &s)
|
|
115
|
+
{
|
|
116
|
+
size_t h = 0;
|
|
117
|
+
auto hashFields = [&](auto... args) { (HashUtils::hash_one(h, args), ...); };
|
|
118
|
+
|
|
119
|
+
auto hashTextLayout = [&](const auto &item) {
|
|
120
|
+
hashFields(item.fontFamily, item.fontSize, item.fontWeight, item.marginTop, item.marginBottom, item.lineHeight);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Block Elements
|
|
124
|
+
hashTextLayout(s.paragraph);
|
|
125
|
+
hashFields(s.paragraph.textAlign);
|
|
126
|
+
hashTextLayout(s.h1);
|
|
127
|
+
hashFields(s.h1.textAlign);
|
|
128
|
+
hashTextLayout(s.h2);
|
|
129
|
+
hashFields(s.h2.textAlign);
|
|
130
|
+
hashTextLayout(s.h3);
|
|
131
|
+
hashFields(s.h3.textAlign);
|
|
132
|
+
hashTextLayout(s.h4);
|
|
133
|
+
hashFields(s.h4.textAlign);
|
|
134
|
+
hashTextLayout(s.h5);
|
|
135
|
+
hashFields(s.h5.textAlign);
|
|
136
|
+
hashTextLayout(s.h6);
|
|
137
|
+
hashFields(s.h6.textAlign);
|
|
138
|
+
|
|
139
|
+
hashTextLayout(s.blockquote);
|
|
140
|
+
hashFields(s.blockquote.borderWidth, s.blockquote.gapWidth, s.blockquote.padding, s.blockquote.borderRadius);
|
|
141
|
+
|
|
142
|
+
hashTextLayout(s.list);
|
|
143
|
+
hashFields(s.list.bulletSize, s.list.markerMinWidth, s.list.markerFontWeight, s.list.gapWidth, s.list.marginLeft,
|
|
144
|
+
s.list.itemSpacing);
|
|
145
|
+
|
|
146
|
+
// Code & Inlines
|
|
147
|
+
hashFields(s.codeBlock.fontFamily, s.codeBlock.fontSize, s.codeBlock.fontWeight, s.codeBlock.marginTop,
|
|
148
|
+
s.codeBlock.marginBottom, s.codeBlock.lineHeight, s.codeBlock.padding, s.codeBlock.borderRadius,
|
|
149
|
+
s.codeBlock.borderWidth);
|
|
150
|
+
hashFields(s.code.fontFamily, s.code.fontSize);
|
|
151
|
+
hashFields(s.link.fontFamily, s.strong.fontFamily, s.strong.fontWeight, s.em.fontFamily, s.em.fontStyle);
|
|
152
|
+
// Variants change link metrics: a font family, or a pill box around the label.
|
|
153
|
+
for (const auto &variant : s.linkVariants) {
|
|
154
|
+
hashFields(variant.pattern, variant.fontFamily, variant.pill.enabled, variant.pill.label, variant.pill.iconUri,
|
|
155
|
+
variant.pill.paddingHorizontal, variant.pill.paddingVertical, variant.pill.lineHeight,
|
|
156
|
+
variant.pill.borderWidth, variant.pill.maxWidth);
|
|
157
|
+
}
|
|
158
|
+
hashFields(s.highlight.backgroundColor, s.highlight.color);
|
|
159
|
+
|
|
160
|
+
// Visual/Spacing Elements
|
|
161
|
+
hashFields(s.image.height, s.image.maxHeight, s.image.aspectRatio, s.image.marginTop, s.image.marginBottom);
|
|
162
|
+
hashFields(s.video.marginTop, s.video.marginBottom, s.video.borderRadius, s.video.aspectRatio,
|
|
163
|
+
s.video.backgroundColor);
|
|
164
|
+
hashFields(s.inlineImage.size);
|
|
165
|
+
hashFields(s.thematicBreak.height, s.thematicBreak.marginTop, s.thematicBreak.marginBottom);
|
|
166
|
+
|
|
167
|
+
// Complex Components
|
|
168
|
+
hashTextLayout(s.table);
|
|
169
|
+
hashFields(s.table.headerFontFamily, s.table.cellPaddingHorizontal, s.table.cellPaddingVertical, s.table.borderWidth,
|
|
170
|
+
s.table.borderRadius, s.table.horizontalOverflow);
|
|
171
|
+
hashFields(s.math.fontSize, s.math.padding, s.math.marginTop, s.math.marginBottom, s.math.textAlign);
|
|
172
|
+
hashFields(s.taskList.checkboxSize, s.taskList.checkboxBorderRadius);
|
|
173
|
+
|
|
174
|
+
return h;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Pill labels and icons (the `linkPillContent` prop) change link widths.
|
|
178
|
+
template <typename ContentVector> inline size_t computeLinkPillContentFingerprint(const ContentVector &content)
|
|
179
|
+
{
|
|
180
|
+
size_t h = 0;
|
|
181
|
+
for (const auto &entry : content) {
|
|
182
|
+
HashUtils::hash_one(h, entry.url);
|
|
183
|
+
HashUtils::hash_one(h, entry.label);
|
|
184
|
+
HashUtils::hash_one(h, entry.iconUri);
|
|
185
|
+
}
|
|
186
|
+
return h;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
template <typename RegexProps> inline std::string buildLinkRecognitionCacheKey(const RegexProps &props)
|
|
190
|
+
{
|
|
191
|
+
std::string key;
|
|
192
|
+
key += props.caseInsensitive ? '1' : '0';
|
|
193
|
+
key += props.dotAll ? '1' : '0';
|
|
194
|
+
key += props.isDisabled ? '1' : '0';
|
|
195
|
+
key += props.isDefault ? '1' : '0';
|
|
196
|
+
return key + props.pattern;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
template <typename PropsType>
|
|
200
|
+
inline MeasurementCacheKey buildMeasurementCacheKey(const PropsType &props, CGFloat maxWidth, CGFloat fontScale,
|
|
201
|
+
TiptapFlavor flavor, size_t wrappedCodeBlocksFingerprint = 0)
|
|
202
|
+
{
|
|
203
|
+
return MeasurementCacheKey{
|
|
204
|
+
.tiptap = props.document,
|
|
205
|
+
.maxWidth = maxWidth,
|
|
206
|
+
.allowTrailingMargin = props.allowTrailingMargin,
|
|
207
|
+
.allowFontScaling = props.allowFontScaling,
|
|
208
|
+
.maxFontSizeMultiplier = props.maxFontSizeMultiplier,
|
|
209
|
+
.md4cFlagsUnderline = props.md4cFlags.underline,
|
|
210
|
+
.md4cFlagsSuperscript = props.md4cFlags.superscript,
|
|
211
|
+
.md4cFlagsSubscript = props.md4cFlags.subscript,
|
|
212
|
+
.md4cFlagsHighlight = props.md4cFlags.highlight,
|
|
213
|
+
.md4cFlagsLatexMath = props.md4cFlags.latexMath,
|
|
214
|
+
.md4cFlagsHardSoftBreaks = props.md4cFlags.hardSoftBreaks,
|
|
215
|
+
.md4cFlagsPreserveBlankLines = props.md4cFlags.preserveBlankLines,
|
|
216
|
+
.md4cFlagsAdmonitions = props.md4cFlags.admonitions,
|
|
217
|
+
.styleFingerprint = computeStyleFingerprint(props.tiptapStyle),
|
|
218
|
+
.linkPillContentFingerprint = computeLinkPillContentFingerprint(props.linkPillContent),
|
|
219
|
+
.wrappedCodeBlocksFingerprint = wrappedCodeBlocksFingerprint,
|
|
220
|
+
.fontScale = fontScale,
|
|
221
|
+
.flavor = flavor,
|
|
222
|
+
.lineBreakStrategyIOS = props.lineBreakStrategyIOS,
|
|
223
|
+
.writingDirection = props.writingDirection,
|
|
224
|
+
.numberOfLines = props.numberOfLines,
|
|
225
|
+
.ellipsizeMode = props.ellipsizeMode,
|
|
226
|
+
.linkRegexKey = buildLinkRecognitionCacheKey(props.linkRecognition.text),
|
|
227
|
+
.inlineCodeLinkRegexKey = buildLinkRecognitionCacheKey(props.linkRecognition.inlineCode),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Thread-safe global measurement cache using an LRU (Least Recently Used) strategy.
|
|
233
|
+
* This ensures O(1) lookups while automatically discarding the oldest entries.
|
|
234
|
+
*/
|
|
235
|
+
class MeasurementCache {
|
|
236
|
+
public:
|
|
237
|
+
struct CacheEntry {
|
|
238
|
+
MeasurementCacheKey key;
|
|
239
|
+
CachedSize size;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
static MeasurementCache &shared()
|
|
243
|
+
{
|
|
244
|
+
static MeasurementCache instance;
|
|
245
|
+
return instance;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
bool get(const MeasurementCacheKey &key, CachedSize &outSize)
|
|
249
|
+
{
|
|
250
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
251
|
+
|
|
252
|
+
auto it = map_.find(key);
|
|
253
|
+
if (it == map_.end()) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
list_.splice(list_.begin(), list_, it->second);
|
|
258
|
+
|
|
259
|
+
outSize = it->second->size;
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
void set(const MeasurementCacheKey &key, CachedSize size)
|
|
264
|
+
{
|
|
265
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
266
|
+
|
|
267
|
+
auto it = map_.find(key);
|
|
268
|
+
if (it != map_.end()) {
|
|
269
|
+
it->second->size = size;
|
|
270
|
+
list_.splice(list_.begin(), list_, it->second);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
list_.push_front({key, size});
|
|
275
|
+
map_[key] = list_.begin();
|
|
276
|
+
|
|
277
|
+
if (map_.size() > kMaxEntries) {
|
|
278
|
+
auto &lastEntry = list_.back();
|
|
279
|
+
map_.erase(lastEntry.key);
|
|
280
|
+
list_.pop_back();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void removeMatchingTiptap(const std::string &tiptap)
|
|
285
|
+
{
|
|
286
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
287
|
+
|
|
288
|
+
for (auto it = list_.begin(); it != list_.end();) {
|
|
289
|
+
if (it->key.tiptap == tiptap) {
|
|
290
|
+
map_.erase(it->key);
|
|
291
|
+
it = list_.erase(it);
|
|
292
|
+
} else {
|
|
293
|
+
++it;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private:
|
|
299
|
+
MeasurementCache() = default;
|
|
300
|
+
|
|
301
|
+
static constexpr size_t kMaxEntries = 512;
|
|
302
|
+
mutable std::mutex mutex_;
|
|
303
|
+
|
|
304
|
+
std::list<CacheEntry> list_;
|
|
305
|
+
std::unordered_map<MeasurementCacheKey, std::list<CacheEntry>::iterator, MeasurementCacheKeyHash> map_;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "MeasurementCache.h"
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
#import <React/RCTUtils.h>
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
#include <cmath>
|
|
8
|
+
#include <react/renderer/core/LayoutConstraints.h>
|
|
9
|
+
#include <react/renderer/core/LayoutContext.h>
|
|
10
|
+
#include <react/utils/ManagedObjectWrapper.h>
|
|
11
|
+
|
|
12
|
+
namespace facebook::react {
|
|
13
|
+
|
|
14
|
+
// Threading contract (issue #550): measureContent may run on any thread while
|
|
15
|
+
// RN holds commit locks that main-thread committers (e.g. Reanimated) also
|
|
16
|
+
// acquire — with `preventShadowTreeCommitExhaustion`, the JS thread re-runs
|
|
17
|
+
// layout under `revisionMutexRecursive_` after 3 failed optimistic commits.
|
|
18
|
+
// Any dispatch_sync to main from this path can therefore deadlock: JS waits
|
|
19
|
+
// for main, main waits for the mutex JS holds (watchdog kill 0x8BADF00D).
|
|
20
|
+
// Nothing in the measurement path may wait on the main thread.
|
|
21
|
+
// EnrichedTiptapText and EnrichedTiptap both measure view-free
|
|
22
|
+
// (ENRMViewFreeMeasurement.h) and comply fully. The one known remaining
|
|
23
|
+
// violation is the text input's own measureContent
|
|
24
|
+
// (EnrichedTiptapTextInputShadowNode.mm), which measures live editable
|
|
25
|
+
// UITextView state and needs its own strategy.
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Font scale (Dynamic Type multiplier) for measurement, without touching the
|
|
29
|
+
* main thread.
|
|
30
|
+
*
|
|
31
|
+
* Reads `LayoutContext::fontSizeMultiplier` instead of calling
|
|
32
|
+
* `RCTFontSizeMultiplier()` (a UIKit read that previously forced a
|
|
33
|
+
* dispatch_sync to main on every measure — a deadlock window under the locked
|
|
34
|
+
* commit fallback, see the contract above). RN maintains the multiplier for
|
|
35
|
+
* us: `RCTFabricSurface::_updateLayoutContext` sets it on main from
|
|
36
|
+
* `RCTFontSizeMultiplier()` and re-runs `constraintLayout` whenever
|
|
37
|
+
* `UIContentSizeCategoryDidChangeNotification` fires, so every Dynamic Type
|
|
38
|
+
* change re-measures with the fresh value. This is the same source
|
|
39
|
+
* `ParagraphShadowNode` uses for core text. A measure racing a Dynamic Type
|
|
40
|
+
* change at worst caches under the outgoing scale, which is never read again
|
|
41
|
+
* once the re-layout lands.
|
|
42
|
+
*/
|
|
43
|
+
static inline CGFloat ENRMFontScaleForMeasurement(bool allowFontScaling, const LayoutContext &layoutContext)
|
|
44
|
+
{
|
|
45
|
+
return allowFontScaling ? layoutContext.fontSizeMultiplier : 1.0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static inline Size ENRMClampMeasuredSize(CGSize size, const LayoutConstraints &layoutConstraints)
|
|
49
|
+
{
|
|
50
|
+
Float clampedWidth = std::max((Float)size.width, layoutConstraints.minimumSize.width);
|
|
51
|
+
clampedWidth = std::min(clampedWidth, layoutConstraints.maximumSize.width);
|
|
52
|
+
Float clampedHeight = std::max((Float)size.height, layoutConstraints.minimumSize.height);
|
|
53
|
+
if (std::isfinite(layoutConstraints.maximumSize.height)) {
|
|
54
|
+
clampedHeight = std::min(clampedHeight, layoutConstraints.maximumSize.height);
|
|
55
|
+
}
|
|
56
|
+
return {clampedWidth, clampedHeight};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
template <typename PropsT>
|
|
60
|
+
static inline bool ENRMPropsNeedExactStreamingMeasurement(const PropsT &oldProps, const PropsT &newProps)
|
|
61
|
+
{
|
|
62
|
+
return oldProps.streamingAnimation != newProps.streamingAnimation ||
|
|
63
|
+
oldProps.allowFontScaling != newProps.allowFontScaling ||
|
|
64
|
+
oldProps.maxFontSizeMultiplier != newProps.maxFontSizeMultiplier ||
|
|
65
|
+
oldProps.allowTrailingMargin != newProps.allowTrailingMargin ||
|
|
66
|
+
oldProps.md4cFlags.underline != newProps.md4cFlags.underline ||
|
|
67
|
+
oldProps.md4cFlags.superscript != newProps.md4cFlags.superscript ||
|
|
68
|
+
oldProps.md4cFlags.subscript != newProps.md4cFlags.subscript ||
|
|
69
|
+
oldProps.md4cFlags.latexMath != newProps.md4cFlags.latexMath ||
|
|
70
|
+
oldProps.md4cFlags.highlight != newProps.md4cFlags.highlight ||
|
|
71
|
+
oldProps.md4cFlags.hardSoftBreaks != newProps.md4cFlags.hardSoftBreaks ||
|
|
72
|
+
oldProps.md4cFlags.preserveBlankLines != newProps.md4cFlags.preserveBlankLines ||
|
|
73
|
+
oldProps.isGFM != newProps.isGFM || oldProps.md4cFlags.admonitions != newProps.md4cFlags.admonitions ||
|
|
74
|
+
computeStyleFingerprint(oldProps.tiptapStyle) != computeStyleFingerprint(newProps.tiptapStyle);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Shared measureContent implementation for the tiptap component views.
|
|
79
|
+
*
|
|
80
|
+
* Owns the thread-safe layers — the streaming fast path (lock-free
|
|
81
|
+
* `ENRMAtomicSize` mailbox published by `updateLayoutMetrics:`), the
|
|
82
|
+
* LRU measurement cache, and the `layoutContext`-sourced font scale — then
|
|
83
|
+
* delegates cache misses to `measureUncached`, through which both components
|
|
84
|
+
* plug their view-free pipeline (`ENRMMeasureTiptapViewFree` /
|
|
85
|
+
* `ENRMMeasureSegmentedTiptapViewFree`); the resolved view is still handed
|
|
86
|
+
* to the block for strategies that can use it. `fontScale` handed to the
|
|
87
|
+
* block is the real multiplier even when streaming skips the cache —
|
|
88
|
+
* rendering must always use it. `wrappedCodeBlocksFingerprint` folds view
|
|
89
|
+
* state outside the props that changes the size (code blocks the user wrapped)
|
|
90
|
+
* into the cache key.
|
|
91
|
+
*/
|
|
92
|
+
template <typename PropsT, typename ViewT>
|
|
93
|
+
static inline Size
|
|
94
|
+
ENRMMeasureTiptapContent(const PropsT &typedProps, const std::shared_ptr<void> &componentViewRef, int receivedCounter,
|
|
95
|
+
int &lastExactMeasurementCounter, CGSize &lastExactMeasurementSize, TiptapFlavor flavor,
|
|
96
|
+
const LayoutContext &layoutContext, const LayoutConstraints &layoutConstraints,
|
|
97
|
+
CGSize (^measureUncached)(ViewT *view, CGFloat maxWidth, CGFloat fontScale),
|
|
98
|
+
size_t wrappedCodeBlocksFingerprint = 0)
|
|
99
|
+
{
|
|
100
|
+
CGFloat maxWidth = layoutConstraints.maximumSize.width;
|
|
101
|
+
|
|
102
|
+
RCTInternalGenericWeakWrapper *weakWrapper = (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentViewRef);
|
|
103
|
+
ViewT *view = weakWrapper ? (ViewT *)weakWrapper.object : nil;
|
|
104
|
+
|
|
105
|
+
// Streaming fast path. Yoga re-measures several times per pass; the first call
|
|
106
|
+
// bumps lastExactMeasurementCounter, the rest land here. Return the freshly
|
|
107
|
+
// measured size, not the view's mailbox — mid-pass the frame isn't committed,
|
|
108
|
+
// so the mailbox is a generation stale and would freeze the height.
|
|
109
|
+
if (typedProps.streamingAnimation && view && receivedCounter <= lastExactMeasurementCounter) {
|
|
110
|
+
if (lastExactMeasurementSize.width > 0 && lastExactMeasurementSize.height > 0) {
|
|
111
|
+
return ENRMClampMeasuredSize(lastExactMeasurementSize, layoutConstraints);
|
|
112
|
+
}
|
|
113
|
+
CGSize currentSize = [view lastCommittedLayoutSize];
|
|
114
|
+
if (currentSize.width > 0 && currentSize.height > 0) {
|
|
115
|
+
return ENRMClampMeasuredSize(currentSize, layoutConstraints);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const bool shouldUseMeasurementCache = !typedProps.streamingAnimation;
|
|
120
|
+
CGFloat fontScale = ENRMFontScaleForMeasurement(typedProps.allowFontScaling, layoutContext);
|
|
121
|
+
|
|
122
|
+
if (shouldUseMeasurementCache && !typedProps.document.empty()) {
|
|
123
|
+
auto cacheKey = buildMeasurementCacheKey(typedProps, maxWidth, fontScale, flavor, wrappedCodeBlocksFingerprint);
|
|
124
|
+
CachedSize cached;
|
|
125
|
+
if (MeasurementCache::shared().get(cacheKey, cached)) {
|
|
126
|
+
return ENRMClampMeasuredSize(CGSizeMake(cached.width, cached.height), layoutConstraints);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
CGSize size = measureUncached(view, maxWidth, fontScale);
|
|
131
|
+
|
|
132
|
+
if (shouldUseMeasurementCache && !typedProps.document.empty()) {
|
|
133
|
+
auto cacheKey = buildMeasurementCacheKey(typedProps, maxWidth, fontScale, flavor, wrappedCodeBlocksFingerprint);
|
|
134
|
+
MeasurementCache::shared().set(cacheKey, {size.width, size.height});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (typedProps.streamingAnimation) {
|
|
138
|
+
lastExactMeasurementCounter = receivedCounter;
|
|
139
|
+
lastExactMeasurementSize = size;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return ENRMClampMeasuredSize(size, layoutConstraints);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import <Foundation/Foundation.h>
|
|
4
|
+
|
|
5
|
+
// Rendering metadata only. Copy reconstruction retains the source semantics.
|
|
6
|
+
static NSString *const ENRMRecognizedLinkAttributeName = @"ENRMRecognizedLink";
|
|
7
|
+
static NSString *const ENRMRecognizedLinkOriginalUnderlineAttributeName = @"ENRMRecognizedLinkOriginalUnderline";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#import "TiptapASTNode.h"
|
|
2
|
+
#import <Foundation/Foundation.h>
|
|
3
|
+
|
|
4
|
+
@interface ENRMMd4cFlags : NSObject <NSCopying>
|
|
5
|
+
|
|
6
|
+
@property (nonatomic, assign) BOOL underline;
|
|
7
|
+
@property (nonatomic, assign) BOOL latexMath;
|
|
8
|
+
@property (nonatomic, assign) BOOL superscript;
|
|
9
|
+
@property (nonatomic, assign) BOOL subscript;
|
|
10
|
+
@property (nonatomic, assign) BOOL highlight;
|
|
11
|
+
@property (nonatomic, assign) BOOL hardSoftBreaks;
|
|
12
|
+
@property (nonatomic, assign) BOOL preserveBlankLines;
|
|
13
|
+
@property (nonatomic, assign) BOOL admonitions;
|
|
14
|
+
|
|
15
|
+
+ (instancetype)defaultFlags;
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
@class ENRMLinkRegexConfig;
|
|
20
|
+
|
|
21
|
+
@interface ENRMTiptapParser : NSObject
|
|
22
|
+
|
|
23
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap;
|
|
24
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags;
|
|
25
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags isGFM:(BOOL)isGFM;
|
|
26
|
+
// Recognition runs before returning the AST to renderers and measurement.
|
|
27
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap
|
|
28
|
+
flags:(ENRMMd4cFlags *)flags
|
|
29
|
+
isGFM:(BOOL)isGFM
|
|
30
|
+
linkRegex:(ENRMLinkRegexConfig *)linkRegex
|
|
31
|
+
inlineCodeLinkRegex:(ENRMLinkRegexConfig *)inlineCodeLinkRegex;
|
|
32
|
+
|
|
33
|
+
@end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#import "ENRMTiptapParser.h"
|
|
2
|
+
#import "ENRMLinkRegexConfig.h"
|
|
3
|
+
#import "TiptapASTNode.h"
|
|
4
|
+
|
|
5
|
+
extern TiptapASTNode *parseTiptapWithCppParser(NSString *tiptap, ENRMMd4cFlags *flags, BOOL isGFM);
|
|
6
|
+
extern TiptapASTNode *parseTiptapWithCppParser(NSString *tiptap, ENRMMd4cFlags *flags, BOOL isGFM,
|
|
7
|
+
ENRMLinkRegexConfig *textRegex, ENRMLinkRegexConfig *codeRegex);
|
|
8
|
+
|
|
9
|
+
@implementation ENRMMd4cFlags
|
|
10
|
+
|
|
11
|
+
- (instancetype)init
|
|
12
|
+
{
|
|
13
|
+
if (self = [super init]) {
|
|
14
|
+
_underline = NO;
|
|
15
|
+
_latexMath = YES;
|
|
16
|
+
_superscript = NO;
|
|
17
|
+
_subscript = NO;
|
|
18
|
+
_highlight = NO;
|
|
19
|
+
_hardSoftBreaks = NO;
|
|
20
|
+
_preserveBlankLines = NO;
|
|
21
|
+
_admonitions = YES;
|
|
22
|
+
}
|
|
23
|
+
return self;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
+ (instancetype)defaultFlags
|
|
27
|
+
{
|
|
28
|
+
return [[ENRMMd4cFlags alloc] init];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (id)copyWithZone:(NSZone *)zone
|
|
32
|
+
{
|
|
33
|
+
ENRMMd4cFlags *copy = [[ENRMMd4cFlags allocWithZone:zone] init];
|
|
34
|
+
copy.underline = self.underline;
|
|
35
|
+
copy.latexMath = self.latexMath;
|
|
36
|
+
copy.superscript = self.superscript;
|
|
37
|
+
copy.subscript = self.subscript;
|
|
38
|
+
copy.highlight = self.highlight;
|
|
39
|
+
copy.hardSoftBreaks = self.hardSoftBreaks;
|
|
40
|
+
copy.preserveBlankLines = self.preserveBlankLines;
|
|
41
|
+
copy.admonitions = self.admonitions;
|
|
42
|
+
return copy;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@end
|
|
46
|
+
|
|
47
|
+
@implementation ENRMTiptapParser
|
|
48
|
+
|
|
49
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap
|
|
50
|
+
{
|
|
51
|
+
return [self parseTiptap:tiptap flags:[ENRMMd4cFlags defaultFlags]];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags
|
|
55
|
+
{
|
|
56
|
+
return [self parseTiptap:tiptap flags:flags isGFM:YES];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags isGFM:(BOOL)isGFM
|
|
60
|
+
{
|
|
61
|
+
return parseTiptapWithCppParser(tiptap, flags, isGFM);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (TiptapASTNode *)parseTiptap:(NSString *)tiptap
|
|
65
|
+
flags:(ENRMMd4cFlags *)flags
|
|
66
|
+
isGFM:(BOOL)isGFM
|
|
67
|
+
linkRegex:(ENRMLinkRegexConfig *)linkRegex
|
|
68
|
+
inlineCodeLinkRegex:(ENRMLinkRegexConfig *)inlineCodeLinkRegex
|
|
69
|
+
{
|
|
70
|
+
return parseTiptapWithCppParser(tiptap, flags, isGFM, linkRegex, inlineCodeLinkRegex);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
typedef NS_ENUM(NSInteger, TiptapNodeType) {
|
|
4
|
+
TiptapNodeTypeDocument,
|
|
5
|
+
TiptapNodeTypeParagraph,
|
|
6
|
+
TiptapNodeTypeText,
|
|
7
|
+
TiptapNodeTypeLink,
|
|
8
|
+
TiptapNodeTypeHeading,
|
|
9
|
+
TiptapNodeTypeLineBreak,
|
|
10
|
+
TiptapNodeTypeStrong,
|
|
11
|
+
TiptapNodeTypeEmphasis,
|
|
12
|
+
TiptapNodeTypeStrikethrough,
|
|
13
|
+
TiptapNodeTypeUnderline,
|
|
14
|
+
TiptapNodeTypeCode,
|
|
15
|
+
TiptapNodeTypeImage,
|
|
16
|
+
TiptapNodeTypeBlockquote,
|
|
17
|
+
TiptapNodeTypeUnorderedList,
|
|
18
|
+
TiptapNodeTypeOrderedList,
|
|
19
|
+
TiptapNodeTypeListItem,
|
|
20
|
+
TiptapNodeTypeCodeBlock,
|
|
21
|
+
TiptapNodeTypeThematicBreak,
|
|
22
|
+
TiptapNodeTypeTable,
|
|
23
|
+
TiptapNodeTypeTableHead,
|
|
24
|
+
TiptapNodeTypeTableBody,
|
|
25
|
+
TiptapNodeTypeTableRow,
|
|
26
|
+
TiptapNodeTypeTableHeaderCell,
|
|
27
|
+
TiptapNodeTypeTableCell,
|
|
28
|
+
TiptapNodeTypeLatexMathInline,
|
|
29
|
+
TiptapNodeTypeLatexMathDisplay,
|
|
30
|
+
TiptapNodeTypeSpoiler,
|
|
31
|
+
TiptapNodeTypeSuperscript,
|
|
32
|
+
TiptapNodeTypeSubscript,
|
|
33
|
+
TiptapNodeTypeHighlight,
|
|
34
|
+
TiptapNodeTypeSoftBreak,
|
|
35
|
+
TiptapNodeTypeBlankLine,
|
|
36
|
+
TiptapNodeTypeAdmonition,
|
|
37
|
+
TiptapNodeTypeVideo,
|
|
38
|
+
TiptapNodeTypeFactoid,
|
|
39
|
+
TiptapNodeTypeMention
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
@interface TiptapASTNode : NSObject
|
|
43
|
+
|
|
44
|
+
@property (nonatomic, assign) TiptapNodeType type;
|
|
45
|
+
@property (nonatomic, strong) NSString *content;
|
|
46
|
+
@property (nonatomic, strong) NSMutableDictionary *attributes;
|
|
47
|
+
@property (nonatomic, strong) NSMutableArray<TiptapASTNode *> *children;
|
|
48
|
+
|
|
49
|
+
- (instancetype)initWithType:(TiptapNodeType)type;
|
|
50
|
+
- (void)addChild:(TiptapASTNode *)child;
|
|
51
|
+
- (void)setAttribute:(NSString *)key value:(NSString *)value;
|
|
52
|
+
|
|
53
|
+
@end
|
|
54
|
+
|
|
55
|
+
/// A node type that md4c emits as a standalone block stacked vertically,
|
|
56
|
+
/// as opposed to an inline span.
|
|
57
|
+
BOOL ENRMIsTopLevelBlockType(TiptapNodeType type);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#import "TiptapASTNode.h"
|
|
2
|
+
|
|
3
|
+
@implementation TiptapASTNode
|
|
4
|
+
|
|
5
|
+
- (instancetype)initWithType:(TiptapNodeType)type
|
|
6
|
+
{
|
|
7
|
+
if (self = [super init]) {
|
|
8
|
+
_type = type;
|
|
9
|
+
_content = nil;
|
|
10
|
+
_attributes = [[NSMutableDictionary alloc] init];
|
|
11
|
+
_children = [[NSMutableArray alloc] init];
|
|
12
|
+
}
|
|
13
|
+
return self;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
- (void)addChild:(TiptapASTNode *)child
|
|
17
|
+
{
|
|
18
|
+
[_children addObject:child];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
- (void)setAttribute:(NSString *)key value:(NSString *)value
|
|
22
|
+
{
|
|
23
|
+
_attributes[key] = value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (NSString *)description
|
|
27
|
+
{
|
|
28
|
+
return [NSString stringWithFormat:@"TiptapASTNode(type=%ld, content=%@, children=%lu)", (long)_type, _content,
|
|
29
|
+
(unsigned long)_children.count];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@end
|
|
33
|
+
|
|
34
|
+
BOOL ENRMIsTopLevelBlockType(TiptapNodeType type)
|
|
35
|
+
{
|
|
36
|
+
switch (type) {
|
|
37
|
+
case TiptapNodeTypeParagraph:
|
|
38
|
+
case TiptapNodeTypeHeading:
|
|
39
|
+
case TiptapNodeTypeCodeBlock:
|
|
40
|
+
case TiptapNodeTypeBlockquote:
|
|
41
|
+
case TiptapNodeTypeAdmonition:
|
|
42
|
+
case TiptapNodeTypeTable:
|
|
43
|
+
case TiptapNodeTypeUnorderedList:
|
|
44
|
+
case TiptapNodeTypeOrderedList:
|
|
45
|
+
case TiptapNodeTypeThematicBreak:
|
|
46
|
+
case TiptapNodeTypeBlankLine:
|
|
47
|
+
case TiptapNodeTypeLatexMathDisplay:
|
|
48
|
+
return YES;
|
|
49
|
+
default:
|
|
50
|
+
return NO;
|
|
51
|
+
}
|
|
52
|
+
}
|