@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,51 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#import "ENRMUIKit.h"
|
|
3
|
+
|
|
4
|
+
@class StyleConfig;
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Adopted by component views that host tiptap text. Notified when a block
|
|
10
|
+
* image resolves its box height after loading (maxHeight/aspectRatio sizing),
|
|
11
|
+
* so the view can drop stale cached measurements and request a height update.
|
|
12
|
+
*/
|
|
13
|
+
@protocol ENRMImageLayoutObserver
|
|
14
|
+
- (void)imageAttachmentDidResolveLayout;
|
|
15
|
+
@end
|
|
16
|
+
|
|
17
|
+
@interface RCTUIView (ENRMImageLayoutObserver)
|
|
18
|
+
/**
|
|
19
|
+
* Nearest ancestor (self included) adopting ENRMImageLayoutObserver, walking up
|
|
20
|
+
* the superview chain. Returns nil when none is found.
|
|
21
|
+
*/
|
|
22
|
+
- (nullable id<ENRMImageLayoutObserver>)enrm_imageLayoutObserver;
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Custom NSTextAttachment for rendering tiptap images.
|
|
27
|
+
* Images are loaded asynchronously and scaled dynamically based on text container width.
|
|
28
|
+
* Supports inline and block images with custom height and border radius from config.
|
|
29
|
+
*/
|
|
30
|
+
@interface ENRMImageAttachment : NSTextAttachment
|
|
31
|
+
|
|
32
|
+
@property (nonatomic, readonly) NSString *imageURL;
|
|
33
|
+
@property (nonatomic, readonly) BOOL isInline;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Invoked on the main thread whenever the image finishes loading/processing.
|
|
37
|
+
* Used by self-drawing hosts (e.g. a table grid) that rasterize the attributed
|
|
38
|
+
* string via -drawWithRect: and therefore never get a live text view for the
|
|
39
|
+
* attachment's normal -refreshDisplay invalidation to reach. Such hosts set this
|
|
40
|
+
* to trigger their own redraw (e.g. -setNeedsDisplay).
|
|
41
|
+
*/
|
|
42
|
+
@property (nonatomic, copy, nullable) void (^onImageLoaded)(void);
|
|
43
|
+
|
|
44
|
+
+ (instancetype)attachmentForURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline;
|
|
45
|
+
|
|
46
|
+
+ (NSCache<NSString *, RCTUIImage *> *)originalImageCache;
|
|
47
|
+
+ (NSCache<NSString *, RCTUIImage *> *)processedImageCache;
|
|
48
|
+
|
|
49
|
+
@end
|
|
50
|
+
|
|
51
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#import "ENRMImageAttachment.h"
|
|
2
|
+
#import "ENRMImageDownloader.h"
|
|
3
|
+
#import "ENRMUIKit.h"
|
|
4
|
+
#import "RuntimeKeys.h"
|
|
5
|
+
#import "StyleConfig.h"
|
|
6
|
+
#import <objc/runtime.h>
|
|
7
|
+
|
|
8
|
+
#define CACHE_KEY_PROCESSED(url, w, h, r, m) [NSString stringWithFormat:@"%@_w%.1f_h%.1f_r%.1f_m%@", url, w, h, r, m]
|
|
9
|
+
|
|
10
|
+
static NSCache<NSString *, RCTUIImage *> *_originalImageCache;
|
|
11
|
+
static NSCache<NSString *, RCTUIImage *> *_processedImageCache;
|
|
12
|
+
|
|
13
|
+
@implementation RCTUIView (ENRMImageLayoutObserver)
|
|
14
|
+
|
|
15
|
+
- (id<ENRMImageLayoutObserver>)enrm_imageLayoutObserver
|
|
16
|
+
{
|
|
17
|
+
RCTUIView *view = self;
|
|
18
|
+
while (view && ![view conformsToProtocol:@protocol(ENRMImageLayoutObserver)]) {
|
|
19
|
+
view = view.superview;
|
|
20
|
+
}
|
|
21
|
+
return (id<ENRMImageLayoutObserver>)view;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
@interface ENRMImageAttachment ()
|
|
27
|
+
|
|
28
|
+
@property (nonatomic, copy) NSString *imageURL;
|
|
29
|
+
@property (nonatomic, copy, nullable) NSDictionary<NSString *, NSString *> *requestHeaders;
|
|
30
|
+
@property (nonatomic, copy) NSString *cacheKey;
|
|
31
|
+
@property (nonatomic, assign) BOOL isInline;
|
|
32
|
+
@property (nonatomic, assign) CGFloat cachedHeight;
|
|
33
|
+
@property (nonatomic, assign) CGFloat cachedMaxHeight;
|
|
34
|
+
@property (nonatomic, assign) CGFloat cachedAspectRatio;
|
|
35
|
+
@property (nonatomic, copy) NSString *cachedResizeMode;
|
|
36
|
+
@property (nonatomic, assign) CGFloat cachedBorderRadius;
|
|
37
|
+
@property (nonatomic, weak) NSTextContainer *textContainer;
|
|
38
|
+
@property (nonatomic, weak) ENRMPlatformTextView *textView;
|
|
39
|
+
@property (nonatomic, strong) RCTUIImage *originalImage;
|
|
40
|
+
@property (nonatomic, strong) RCTUIImage *loadedImage;
|
|
41
|
+
@property (nonatomic, strong) RCTUIImage *placeholderImage;
|
|
42
|
+
@property (nonatomic, copy) NSString *lastProcessedKey;
|
|
43
|
+
|
|
44
|
+
@end
|
|
45
|
+
|
|
46
|
+
@implementation ENRMImageAttachment
|
|
47
|
+
|
|
48
|
+
+ (NSCache<NSString *, RCTUIImage *> *)originalImageCache
|
|
49
|
+
{
|
|
50
|
+
static dispatch_once_t onceToken;
|
|
51
|
+
dispatch_once(&onceToken, ^{
|
|
52
|
+
_originalImageCache = [[NSCache alloc] init];
|
|
53
|
+
_originalImageCache.countLimit = 50;
|
|
54
|
+
_originalImageCache.totalCostLimit = 1024 * 1024 * 20; // 20 MB
|
|
55
|
+
});
|
|
56
|
+
return _originalImageCache;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
+ (NSCache<NSString *, RCTUIImage *> *)processedImageCache
|
|
60
|
+
{
|
|
61
|
+
static dispatch_once_t onceToken;
|
|
62
|
+
dispatch_once(&onceToken, ^{
|
|
63
|
+
_processedImageCache = [[NSCache alloc] init];
|
|
64
|
+
_processedImageCache.countLimit = 100;
|
|
65
|
+
_processedImageCache.totalCostLimit = 1024 * 1024 * 30; // 30 MB
|
|
66
|
+
});
|
|
67
|
+
return _processedImageCache;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
+ (instancetype)attachmentForURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline
|
|
71
|
+
{
|
|
72
|
+
// Always a fresh instance, never shared across positions: the table renderer can draw
|
|
73
|
+
// the same image URL at a different width than a copy outside the table, and a shared
|
|
74
|
+
// NSTextAttachment would thrash its single last-processed width into a redraw loop. The
|
|
75
|
+
// image caches keep fresh instances cheap (no re-fetch or re-scale).
|
|
76
|
+
return [[self alloc] initWithImageURL:imageURL config:config isInline:isInline];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
- (instancetype)initWithImageURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline
|
|
80
|
+
{
|
|
81
|
+
self = [super init];
|
|
82
|
+
if (self) {
|
|
83
|
+
_imageURL = imageURL;
|
|
84
|
+
_requestHeaders = [[config imageRequestHeaders] copy];
|
|
85
|
+
_cacheKey = ENRMImageCacheKey(imageURL, _requestHeaders);
|
|
86
|
+
_isInline = isInline;
|
|
87
|
+
|
|
88
|
+
_cachedHeight = isInline ? [config inlineImageSize] : [config imageHeight];
|
|
89
|
+
_cachedMaxHeight = [config imageMaxHeight];
|
|
90
|
+
_cachedAspectRatio = [config imageAspectRatio];
|
|
91
|
+
_cachedResizeMode = [config imageResizeMode];
|
|
92
|
+
_cachedBorderRadius = [config imageBorderRadius];
|
|
93
|
+
|
|
94
|
+
[self setupPlaceholder];
|
|
95
|
+
[self startDownloadingImage];
|
|
96
|
+
}
|
|
97
|
+
return self;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
- (CGFloat)resolvedBoxHeightForWidth:(CGFloat)width
|
|
101
|
+
{
|
|
102
|
+
if (self.cachedAspectRatio > 0 && width > 0) {
|
|
103
|
+
return width / self.cachedAspectRatio;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (self.cachedMaxHeight > 0) {
|
|
107
|
+
RCTUIImage *source = self.originalImage;
|
|
108
|
+
if (source && width > 0 && source.size.width > 0 && source.size.height > 0) {
|
|
109
|
+
CGFloat fitted = width * source.size.height / source.size.width;
|
|
110
|
+
return MIN(self.cachedMaxHeight, fitted);
|
|
111
|
+
}
|
|
112
|
+
// Intrinsic size not known yet — fall back to the full max height; the box
|
|
113
|
+
// shrinks once the image loads and layout is invalidated.
|
|
114
|
+
return self.cachedMaxHeight;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return self.cachedHeight;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// True when resizeMode is unset ('') - legacy always implies a fixed height box.
|
|
121
|
+
|
|
122
|
+
- (BOOL)isLegacyBlockSizing
|
|
123
|
+
{
|
|
124
|
+
return !self.isInline && self.cachedResizeMode.length == 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
- (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer
|
|
128
|
+
proposedLineFragment:(CGRect)lineFragment
|
|
129
|
+
glyphPosition:(CGPoint)position
|
|
130
|
+
characterIndex:(NSUInteger)characterIndex
|
|
131
|
+
{
|
|
132
|
+
CGFloat height = self.cachedHeight;
|
|
133
|
+
CGFloat width = self.isInline ? height : (lineFragment.size.width > 0 ? lineFragment.size.width : height);
|
|
134
|
+
|
|
135
|
+
if (!self.isInline) {
|
|
136
|
+
height = [self resolvedBoxHeightForWidth:width];
|
|
137
|
+
return CGRectMake(0, 0, width, height);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
UIFont *appliedFont = nil;
|
|
141
|
+
NSLayoutManager *layoutManager = textContainer.layoutManager;
|
|
142
|
+
NSTextStorage *textStorage = layoutManager.textStorage;
|
|
143
|
+
|
|
144
|
+
if (textStorage && characterIndex < textStorage.length) {
|
|
145
|
+
appliedFont = [textStorage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
CGFloat verticalOffset;
|
|
149
|
+
if (appliedFont) {
|
|
150
|
+
verticalOffset = (appliedFont.capHeight - height) / 2.0;
|
|
151
|
+
} else {
|
|
152
|
+
verticalOffset = (lineFragment.size.height - height) / 2.0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return CGRectMake(0, verticalOffset, width, height);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
- (RCTUIImage *)imageForBounds:(CGRect)imageBounds
|
|
159
|
+
textContainer:(NSTextContainer *)textContainer
|
|
160
|
+
characterIndex:(NSUInteger)characterIndex
|
|
161
|
+
{
|
|
162
|
+
self.textContainer = textContainer;
|
|
163
|
+
|
|
164
|
+
if (self.originalImage && imageBounds.size.width > 0) {
|
|
165
|
+
self.bounds = imageBounds;
|
|
166
|
+
[self processAndApplyImage:self.originalImage withTargetWidth:imageBounds.size.width];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return self.loadedImage ?: self.placeholderImage;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
- (void)handleLoadedImage:(RCTUIImage *)image
|
|
173
|
+
{
|
|
174
|
+
if (!image)
|
|
175
|
+
return;
|
|
176
|
+
|
|
177
|
+
// The downloader completes synchronously on cache hits, which can happen on the render queue
|
|
178
|
+
if (!NSThread.isMainThread) {
|
|
179
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [self handleLoadedImage:image]; });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
self.originalImage = image;
|
|
184
|
+
// UIKit reads the plain image property for save/drag/copy — it must hold the original
|
|
185
|
+
self.image = image;
|
|
186
|
+
CGFloat targetWidth = self.isInline ? self.cachedHeight : self.bounds.size.width;
|
|
187
|
+
|
|
188
|
+
// Defer processing if we don't have valid bounds yet (common for non-inline block images)
|
|
189
|
+
if (!self.isInline && targetWidth <= 0) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
[self processAndApplyImage:image withTargetWidth:targetWidth];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
- (void)processAndApplyImage:(RCTUIImage *)image withTargetWidth:(CGFloat)targetWidth
|
|
197
|
+
{
|
|
198
|
+
if (targetWidth <= 0)
|
|
199
|
+
return;
|
|
200
|
+
|
|
201
|
+
CGFloat boxHeight = self.isInline ? self.cachedHeight : [self resolvedBoxHeightForWidth:targetWidth];
|
|
202
|
+
|
|
203
|
+
NSString *processedKey =
|
|
204
|
+
CACHE_KEY_PROCESSED(self.cacheKey, targetWidth, boxHeight, self.cachedBorderRadius, self.cachedResizeMode);
|
|
205
|
+
|
|
206
|
+
if ([processedKey isEqualToString:self.lastProcessedKey])
|
|
207
|
+
return;
|
|
208
|
+
self.lastProcessedKey = processedKey;
|
|
209
|
+
|
|
210
|
+
RCTUIImage *cachedProcessed = [[ENRMImageAttachment processedImageCache] objectForKey:processedKey];
|
|
211
|
+
|
|
212
|
+
if (cachedProcessed) {
|
|
213
|
+
self.loadedImage = cachedProcessed;
|
|
214
|
+
[self refreshDisplay];
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
__weak typeof(self) weakSelf = self;
|
|
219
|
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
|
220
|
+
__strong typeof(weakSelf) strongSelf = weakSelf;
|
|
221
|
+
if (!strongSelf)
|
|
222
|
+
return;
|
|
223
|
+
|
|
224
|
+
RCTUIImage *processedImage = [strongSelf createScaledImage:image
|
|
225
|
+
toWidth:targetWidth
|
|
226
|
+
height:boxHeight
|
|
227
|
+
borderRadius:strongSelf.cachedBorderRadius];
|
|
228
|
+
|
|
229
|
+
if (processedImage) {
|
|
230
|
+
[[ENRMImageAttachment processedImageCache] setObject:processedImage
|
|
231
|
+
forKey:processedKey
|
|
232
|
+
cost:ENRMImageByteCost(processedImage)];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
236
|
+
strongSelf.loadedImage = processedImage;
|
|
237
|
+
if (strongSelf.isInline) {
|
|
238
|
+
strongSelf.bounds = CGRectMake(0, 0, strongSelf.cachedHeight, strongSelf.cachedHeight);
|
|
239
|
+
}
|
|
240
|
+
[strongSelf refreshDisplay];
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
- (RCTUIImage *)createScaledImage:(RCTUIImage *)image
|
|
246
|
+
toWidth:(CGFloat)targetWidth
|
|
247
|
+
height:(CGFloat)targetHeight
|
|
248
|
+
borderRadius:(CGFloat)radius
|
|
249
|
+
{
|
|
250
|
+
CGFloat sourceWidth = image.size.width;
|
|
251
|
+
CGFloat sourceHeight = image.size.height;
|
|
252
|
+
if (sourceWidth <= 0 || sourceHeight <= 0)
|
|
253
|
+
return nil;
|
|
254
|
+
|
|
255
|
+
CGSize source = CGSizeMake(sourceWidth, sourceHeight);
|
|
256
|
+
CGSize box = CGSizeMake(targetWidth, targetHeight);
|
|
257
|
+
BOOL legacy = [self isLegacyBlockSizing];
|
|
258
|
+
|
|
259
|
+
CGRect drawingRect;
|
|
260
|
+
if (self.isInline || legacy) {
|
|
261
|
+
CGFloat drawingWidth, drawingHeight;
|
|
262
|
+
if (!self.isInline) {
|
|
263
|
+
CGFloat aspectRatioScale = targetWidth / sourceWidth;
|
|
264
|
+
drawingWidth = targetWidth;
|
|
265
|
+
drawingHeight = sourceHeight * aspectRatioScale;
|
|
266
|
+
} else {
|
|
267
|
+
drawingWidth = targetWidth;
|
|
268
|
+
drawingHeight = targetHeight;
|
|
269
|
+
}
|
|
270
|
+
drawingRect = CGRectMake((targetWidth - drawingWidth) / 2.0, (targetHeight - drawingHeight) / 2.0, drawingWidth,
|
|
271
|
+
drawingHeight);
|
|
272
|
+
} else {
|
|
273
|
+
drawingRect = [self drawingRectForResizeMode:self.cachedResizeMode source:source box:box];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
RCTUIGraphicsImageRenderer *renderer = ImageRendererForSize(box);
|
|
277
|
+
|
|
278
|
+
return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *context) {
|
|
279
|
+
if (radius > 0) {
|
|
280
|
+
CGRect clipRect = CGRectIntersection(CGRectMake(0, 0, targetWidth, targetHeight), drawingRect);
|
|
281
|
+
UIBezierPath *path = UIBezierPathWithRoundedRect(clipRect, radius);
|
|
282
|
+
[path addClip];
|
|
283
|
+
}
|
|
284
|
+
[image drawInRect:drawingRect];
|
|
285
|
+
}];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
- (CGRect)drawingRectForResizeMode:(NSString *)mode source:(CGSize)source box:(CGSize)box
|
|
289
|
+
{
|
|
290
|
+
if ([mode isEqualToString:@"stretch"]) {
|
|
291
|
+
return CGRectMake(0, 0, box.width, box.height);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
CGFloat widthScale = box.width / source.width;
|
|
295
|
+
CGFloat heightScale = box.height / source.height;
|
|
296
|
+
|
|
297
|
+
CGFloat scale;
|
|
298
|
+
if ([mode isEqualToString:@"contain"]) {
|
|
299
|
+
scale = MIN(widthScale, heightScale);
|
|
300
|
+
} else if ([mode isEqualToString:@"center"]) {
|
|
301
|
+
scale = MIN(1.0, MIN(widthScale, heightScale));
|
|
302
|
+
} else if ([mode isEqualToString:@"none"]) {
|
|
303
|
+
scale = 1.0;
|
|
304
|
+
} else { // cover (default)
|
|
305
|
+
scale = MAX(widthScale, heightScale);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
CGFloat drawingWidth = source.width * scale;
|
|
309
|
+
CGFloat drawingHeight = source.height * scale;
|
|
310
|
+
return CGRectMake((box.width - drawingWidth) / 2.0, (box.height - drawingHeight) / 2.0, drawingWidth, drawingHeight);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
- (void)startDownloadingImage
|
|
314
|
+
{
|
|
315
|
+
if (self.imageURL.length == 0)
|
|
316
|
+
return;
|
|
317
|
+
|
|
318
|
+
__weak typeof(self) weakSelf = self;
|
|
319
|
+
[[ENRMImageDownloader shared] downloadURL:self.imageURL
|
|
320
|
+
headers:self.requestHeaders
|
|
321
|
+
completion:^(RCTUIImage *image) { [weakSelf handleLoadedImage:image]; }];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
- (void)refreshDisplay
|
|
325
|
+
{
|
|
326
|
+
// Notify self-drawing hosts (e.g. a table grid) that rasterize us via
|
|
327
|
+
// -drawWithRect: and have no live text view for the invalidation below to reach.
|
|
328
|
+
if (self.onImageLoaded) {
|
|
329
|
+
self.onImageLoaded();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
UITextView *textView = [self fetchAssociatedTextView];
|
|
333
|
+
if (!textView)
|
|
334
|
+
return;
|
|
335
|
+
|
|
336
|
+
NSRange range = [self findAttachmentRangeInText:textView.textStorage];
|
|
337
|
+
if (range.location != NSNotFound) {
|
|
338
|
+
[textView.layoutManager invalidateDisplayForCharacterRange:range];
|
|
339
|
+
if (!self.isInline) {
|
|
340
|
+
[textView.layoutManager invalidateLayoutForCharacterRange:range actualCharacterRange:NULL];
|
|
341
|
+
[self notifyImageLayoutObserver:textView];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// With maxHeight/aspectRatio sizing the box height can settle after the image
|
|
347
|
+
// loads, while the component was measured (and its size cached) with the
|
|
348
|
+
// pre-load fallback. Notify the hosting component so it can re-measure.
|
|
349
|
+
// Dispatched async: refreshDisplay can run mid-layout (imageForBounds) and
|
|
350
|
+
// re-measuring would re-enter the layout manager.
|
|
351
|
+
- (void)notifyImageLayoutObserver:(UITextView *)textView
|
|
352
|
+
{
|
|
353
|
+
// Only maxHeight/aspectRatio boxes can change height after load; a fixed
|
|
354
|
+
// height box (legacy or explicit resizeMode) never needs a re-measure.
|
|
355
|
+
if (self.cachedMaxHeight <= 0 && self.cachedAspectRatio <= 0)
|
|
356
|
+
return;
|
|
357
|
+
|
|
358
|
+
id<ENRMImageLayoutObserver> observer = [textView enrm_imageLayoutObserver];
|
|
359
|
+
if (!observer)
|
|
360
|
+
return;
|
|
361
|
+
|
|
362
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [observer imageAttachmentDidResolveLayout]; });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
- (ENRMPlatformTextView *)fetchAssociatedTextView
|
|
366
|
+
{
|
|
367
|
+
if (self.textView)
|
|
368
|
+
return self.textView;
|
|
369
|
+
if (!self.textContainer)
|
|
370
|
+
return nil;
|
|
371
|
+
self.textView = objc_getAssociatedObject(self.textContainer, kTextViewKey);
|
|
372
|
+
return self.textView;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
- (void)setupPlaceholder
|
|
376
|
+
{
|
|
377
|
+
CGFloat size = self.cachedHeight;
|
|
378
|
+
self.bounds = CGRectMake(0, 0, size, size);
|
|
379
|
+
RCTUIGraphicsImageRenderer *renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(1, 1)];
|
|
380
|
+
self.placeholderImage = [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *ctx){}];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
- (NSRange)findAttachmentRangeInText:(NSAttributedString *)attributedString
|
|
384
|
+
{
|
|
385
|
+
__block NSRange foundRange = NSMakeRange(NSNotFound, 0);
|
|
386
|
+
[attributedString enumerateAttribute:NSAttachmentAttributeName
|
|
387
|
+
inRange:NSMakeRange(0, attributedString.length)
|
|
388
|
+
options:0
|
|
389
|
+
usingBlock:^(id value, NSRange range, BOOL *stop) {
|
|
390
|
+
if (value == self) {
|
|
391
|
+
foundRange = range;
|
|
392
|
+
*stop = YES;
|
|
393
|
+
}
|
|
394
|
+
}];
|
|
395
|
+
return foundRange;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
@end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#import "ENRMUIKit.h"
|
|
3
|
+
|
|
4
|
+
#if !TARGET_OS_OSX
|
|
5
|
+
@class LinkVariantConfig;
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A link presented as a pill. Like image and inline-math attachments it is a
|
|
11
|
+
* single U+FFFC in text storage, laid out and drawn by TextKit natively.
|
|
12
|
+
* The link's own rendered text is kept here; ENRMLinkPillText.h puts it back
|
|
13
|
+
* wherever text leaves the view (copy, export, accessibility).
|
|
14
|
+
*/
|
|
15
|
+
@interface ENRMLinkPillAttachment : NSTextAttachment
|
|
16
|
+
@property (nonatomic, readonly) CGFloat boxHeight;
|
|
17
|
+
/// The minimum line height the pill asks of the block that holds it (`pill.lineHeight`); 0 for none.
|
|
18
|
+
@property (nonatomic, assign) CGFloat lineHeight;
|
|
19
|
+
/// The text the pill shows.
|
|
20
|
+
@property (nonatomic, readonly) NSString *label;
|
|
21
|
+
/// Visible label, followed by the original link text when they differ.
|
|
22
|
+
@property (nonatomic, readonly) NSString *linkAccessibilityLabel;
|
|
23
|
+
@property (nonatomic, readonly) NSAttributedString *originalText;
|
|
24
|
+
/// The radius the pill's corners are drawn with.
|
|
25
|
+
@property (nonatomic, readonly) CGFloat cornerRadius;
|
|
26
|
+
/// Draws nothing while set. The text view sets it while the pill is lifted for its menu,
|
|
27
|
+
/// so that the lifted copy is the only one on screen.
|
|
28
|
+
@property (nonatomic, assign) BOOL lifted;
|
|
29
|
+
/// Called on the main thread when an asynchronously loaded icon settles. For hosts that draw the
|
|
30
|
+
/// string themselves (the table grid) and have no text view for the attachment to invalidate.
|
|
31
|
+
@property (nonatomic, copy, nullable) void (^onIconLoaded)(void);
|
|
32
|
+
|
|
33
|
+
/// `variant.pill` must be non-nil. `label`, `iconUri` and `iconTintColor` are already resolved (per-link content,
|
|
34
|
+
/// then variant default).
|
|
35
|
+
- (instancetype)initWithOriginalText:(NSAttributedString *)originalText
|
|
36
|
+
variant:(LinkVariantConfig *)variant
|
|
37
|
+
label:(nullable NSString *)label
|
|
38
|
+
iconUri:(nullable NSString *)iconUri
|
|
39
|
+
iconTintColor:(nullable UIColor *)iconTintColor
|
|
40
|
+
font:(nullable UIFont *)font
|
|
41
|
+
requestHeaders:(nullable NSDictionary<NSString *, NSString *> *)requestHeaders;
|
|
42
|
+
|
|
43
|
+
- (void)adoptFont:(nullable UIFont *)font;
|
|
44
|
+
@end
|
|
45
|
+
|
|
46
|
+
NS_ASSUME_NONNULL_END
|
|
47
|
+
#endif
|