@mathers101/react-native-render-rich-text 0.1.10 → 0.1.14
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 -20
- package/README.md +140 -140
- package/ReactNativeRenderRichText.podspec +23 -23
- package/android/build.gradle +86 -86
- package/android/consumer-rules.pro +3 -3
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -24
- package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -13
- package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -644
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -17
- package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -112
- package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -576
- package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -24
- package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -28
- package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -24
- package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -29
- package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -23
- package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -23
- package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -25
- package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -26
- package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -9
- package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -59
- package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -35
- package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -45
- package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -39
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -243
- package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -56
- package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -135
- package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -37
- package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -81
- package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -26
- package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -17
- package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -90
- package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -109
- package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -211
- package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -133
- package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -85
- package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -91
- package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -148
- package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -17
- package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -143
- package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -31
- package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -46
- package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -28
- package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -164
- package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -27
- package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -302
- package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -205
- package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -216
- package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -32
- package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -42
- package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -29
- package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -38
- package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -80
- package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -481
- package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -42
- package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -39
- package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -154
- package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -381
- package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -68
- package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -33
- package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -38
- package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -76
- package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -132
- package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -46
- package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -127
- package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -33
- package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -12
- package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -39
- package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -143
- package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -26
- package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -69
- package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -96
- package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -46
- package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -11
- package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -83
- package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -80
- package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -26
- package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -33
- package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -19
- package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -36
- package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -44
- package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -23
- package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -34
- package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -65
- package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -19
- package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -33
- package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -27
- package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -21
- package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -411
- package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -92
- package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -16
- package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -16
- package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -75
- package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -29
- package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -32
- package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -23
- package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -17
- package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -31
- package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -86
- package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -32
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -36
- package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -42
- package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -27
- package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -10
- package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -31
- package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -56
- package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -18
- package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -28
- package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -6
- package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -368
- package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -88
- package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -203
- package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -167
- package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -84
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -1105
- package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -423
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -9
- package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -76
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -61
- package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -286
- package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -39
- package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -142
- package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -43
- package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -30
- package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -15
- package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -19
- package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -235
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -48
- package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -119
- package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -217
- package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -101
- package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -40
- package/android/src/main/jni/CMakeLists.txt +52 -52
- package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -30
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -29
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -45
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -21
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -38
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -53
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -9
- package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -24
- package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -40
- package/cpp/parser/TiptapParser.hpp +13 -13
- package/cpp/vendor/nlohmann/json.hpp +24765 -24765
- package/ios/EnrichedTiptapText.h +27 -27
- package/ios/attachments/ENRMImageAttachment.h +51 -51
- package/ios/attachments/ENRMImageAttachment.m +398 -398
- package/ios/attachments/ENRMLinkPillAttachment.h +47 -47
- package/ios/attachments/ENRMLinkPillAttachment.m +324 -324
- package/ios/attachments/ENRMLinkPillIconCache.h +28 -28
- package/ios/attachments/ENRMLinkPillIconCache.m +181 -181
- package/ios/attachments/ENRMLinkPillText.h +27 -27
- package/ios/attachments/ENRMLinkPillText.m +118 -118
- package/ios/attachments/ENRMMathInlineAttachment.h +7 -7
- package/ios/attachments/ENRMMathInlineAttachment.m +4 -4
- package/ios/attachments/ThematicBreakAttachment.h +15 -15
- package/ios/attachments/ThematicBreakAttachment.m +33 -33
- package/ios/internals/ENRMViewFreeMeasurement.h +208 -208
- package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -19
- package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -43
- package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -69
- package/ios/internals/EnrichedTiptapTextState.h +24 -24
- package/ios/internals/MeasurementCache.h +308 -308
- package/ios/internals/ShadowMeasurementUtils.h +145 -145
- package/ios/parser/ENRMTextLinkAttributes.h +7 -7
- package/ios/parser/ENRMTiptapParser.h +33 -33
- package/ios/parser/ENRMTiptapParser.mm +73 -73
- package/ios/parser/TiptapASTNode.m +52 -52
- package/ios/renderer/AttributedRenderer.h +23 -23
- package/ios/renderer/AttributedRenderer.m +229 -229
- package/ios/renderer/BaseRenderer.h +33 -33
- package/ios/renderer/BaseRenderer.m +46 -46
- package/ios/renderer/BaselineShiftTextAttributes.h +10 -10
- package/ios/renderer/BaselineShiftTextAttributes.m +26 -26
- package/ios/renderer/BlankLineRenderer.h +4 -4
- package/ios/renderer/BlankLineRenderer.m +51 -51
- package/ios/renderer/BlockquoteRenderer.h +6 -6
- package/ios/renderer/BlockquoteRenderer.m +258 -258
- package/ios/renderer/CodeBlockRenderer.h +9 -9
- package/ios/renderer/CodeBlockRenderer.m +99 -99
- package/ios/renderer/CodeRenderer.h +9 -9
- package/ios/renderer/CodeRenderer.m +69 -69
- package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -25
- package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -48
- package/ios/renderer/EmphasisRenderer.h +5 -5
- package/ios/renderer/EmphasisRenderer.m +99 -99
- package/ios/renderer/HeadingRenderer.h +6 -6
- package/ios/renderer/HeadingRenderer.m +102 -102
- package/ios/renderer/HighlightRenderer.h +7 -7
- package/ios/renderer/HighlightRenderer.m +33 -33
- package/ios/renderer/LinkRenderer.h +6 -6
- package/ios/renderer/LinkRenderer.m +157 -157
- package/ios/renderer/ListItemRenderer.h +24 -24
- package/ios/renderer/ListItemRenderer.m +283 -283
- package/ios/renderer/ListRenderer.h +13 -13
- package/ios/renderer/ListRenderer.m +126 -126
- package/ios/renderer/MentionRenderer.h +9 -9
- package/ios/renderer/MentionRenderer.m +96 -96
- package/ios/renderer/NodeRenderer.h +8 -8
- package/ios/renderer/ParagraphRenderer.h +6 -6
- package/ios/renderer/ParagraphRenderer.m +85 -85
- package/ios/renderer/RenderContext.h +145 -145
- package/ios/renderer/RenderContext.m +402 -402
- package/ios/renderer/RendererFactory.h +12 -12
- package/ios/renderer/StrikethroughRenderer.h +5 -5
- package/ios/renderer/StrikethroughRenderer.m +30 -30
- package/ios/renderer/StrongRenderer.h +5 -5
- package/ios/renderer/StrongRenderer.m +87 -87
- package/ios/renderer/TextRenderer.h +6 -6
- package/ios/renderer/TextRenderer.m +18 -18
- package/ios/renderer/ThematicBreakRenderer.h +4 -4
- package/ios/renderer/ThematicBreakRenderer.m +41 -41
- package/ios/renderer/UnderlineRenderer.h +4 -4
- package/ios/renderer/UnderlineRenderer.m +41 -41
- package/ios/styles/ENRMFontSlot.h +12 -12
- package/ios/styles/ENRMFontSlot.m +24 -24
- package/ios/styles/StyleConfig.h +488 -488
- package/ios/styles/StyleConfig.mm +2820 -2820
- package/ios/utils/AccessibilityInfo.h +35 -35
- package/ios/utils/AccessibilityInfo.m +24 -24
- package/ios/utils/BlockquoteBorder.h +26 -26
- package/ios/utils/BlockquoteBorder.m +294 -294
- package/ios/utils/CodeBackground.h +19 -19
- package/ios/utils/CodeBackground.m +196 -196
- package/ios/utils/CodeBlockBackground.h +17 -17
- package/ios/utils/CodeBlockBackground.m +102 -102
- package/ios/utils/ContextMenuUtils.h +76 -76
- package/ios/utils/ContextMenuUtils.mm +75 -75
- package/ios/utils/ENRMAccessibilityLabels.h +40 -40
- package/ios/utils/ENRMAccessibilityLabels.m +5 -5
- package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -24
- package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -37
- package/ios/utils/ENRMAtomicSize.h +65 -65
- package/ios/utils/ENRMCodeBlockContent.h +37 -37
- package/ios/utils/ENRMCodeBlockContent.mm +89 -89
- package/ios/utils/ENRMFeatureFlags.h +25 -25
- package/ios/utils/ENRMImageDownloader.h +30 -30
- package/ios/utils/ENRMImageDownloader.m +168 -168
- package/ios/utils/ENRMLatexErrorCoordinator.h +27 -27
- package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -75
- package/ios/utils/ENRMLatexErrorReporting.h +13 -13
- package/ios/utils/ENRMLinkContextMenus.h +93 -93
- package/ios/utils/ENRMLinkContextMenus.m +178 -178
- package/ios/utils/ENRMLinkRegexConfig.h +30 -30
- package/ios/utils/ENRMLinkRegexConfig.mm +104 -104
- package/ios/utils/ENRMLinkRegexProps.h +23 -23
- package/ios/utils/ENRMLocalImageLoader.h +35 -35
- package/ios/utils/ENRMLocalImageLoader.m +111 -111
- package/ios/utils/ENRMMenuAction.h +27 -27
- package/ios/utils/ENRMMenuAction.m +33 -33
- package/ios/utils/ENRMSpoilerOverlayManager.h +15 -15
- package/ios/utils/ENRMSpoilerOverlayManager.m +19 -19
- package/ios/utils/ENRMSpoilerTapUtils.h +6 -6
- package/ios/utils/ENRMSpoilerTapUtils.m +11 -11
- package/ios/utils/ENRMTailFadeInAnimator.h +16 -16
- package/ios/utils/ENRMTailFadeInAnimator.m +161 -161
- package/ios/utils/ENRMTextHitTest.h +23 -23
- package/ios/utils/ENRMTextHitTest.m +20 -20
- package/ios/utils/ENRMTextInteractionUtils.h +20 -20
- package/ios/utils/ENRMTextInteractionUtils.m +15 -15
- package/ios/utils/ENRMTextRenderer.h +38 -38
- package/ios/utils/ENRMTextRenderer.m +54 -54
- package/ios/utils/ENRMTextViewSetup.h +132 -132
- package/ios/utils/ENRMUIKit.h +429 -429
- package/ios/utils/EditMenuUtils.h +105 -105
- package/ios/utils/EditMenuUtils.m +143 -143
- package/ios/utils/FontScaleObserver.h +10 -10
- package/ios/utils/FontScaleObserver.m +55 -55
- package/ios/utils/FontUtils.h +31 -31
- package/ios/utils/FontUtils.m +63 -63
- package/ios/utils/HTMLGenerator.h +25 -25
- package/ios/utils/HTMLGenerator.m +1041 -1041
- package/ios/utils/HeightUpdateUtils.h +25 -25
- package/ios/utils/ImageRequestHeaderUtils.h +35 -35
- package/ios/utils/LastElementUtils.h +97 -97
- package/ios/utils/LinkContextMenuUtils.h +55 -55
- package/ios/utils/LinkPillContentUtils.h +46 -46
- package/ios/utils/ListMarkerDrawer.h +15 -15
- package/ios/utils/ListMarkerDrawer.m +239 -239
- package/ios/utils/MentionBackground.h +26 -26
- package/ios/utils/MentionBackground.m +86 -86
- package/ios/utils/ParagraphStyleUtils.h +87 -87
- package/ios/utils/ParagraphStyleUtils.m +484 -484
- package/ios/utils/PasteboardUtils.h +48 -48
- package/ios/utils/PasteboardUtils.m +166 -166
- package/ios/utils/RTFExportUtils.h +24 -24
- package/ios/utils/RTFExportUtils.m +299 -299
- package/ios/utils/SelectionColorUtils.h +14 -14
- package/ios/utils/StylePropsUtils.h +1340 -1340
- package/ios/utils/TaskListTapUtils.h +6 -6
- package/ios/utils/TaskListTapUtils.m +14 -14
- package/ios/utils/TextViewLayoutManager.h +14 -14
- package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -43
- package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -432
- package/ios/utils/TiptapExtractor.h +17 -17
- package/ios/utils/TiptapExtractor.m +367 -367
- package/ios/views/ENRMTiptapTextView.h +25 -25
- package/ios/views/ENRMTiptapTextView.m +247 -247
- package/package.json +65 -70
- package/react-native.config.js +10 -10
- package/src/admonitionDefaults.ts +58 -58
- package/src/darkModeTextStyle.ts +99 -99
- package/src/headingDefaults.ts +21 -21
- package/src/index.tsx +4 -4
- package/src/linkVariantUtils.ts +120 -120
- package/src/normalizeTiptapStyle.ts +397 -397
- package/src/rn-globals.d.ts +1 -1
- package/src/styleUtils.ts +107 -107
- package/src/types/TiptapStyle.ts +532 -532
- package/src/types/TiptapStyleInternal.ts +299 -299
- package/src/types/linkPill.ts +9 -9
- package/src/utils/isDev.ts +4 -4
|
@@ -1,484 +1,484 @@
|
|
|
1
|
-
#import "ParagraphStyleUtils.h"
|
|
2
|
-
#import "ENRMFeatureFlags.h"
|
|
3
|
-
#import "ENRMImageAttachment.h"
|
|
4
|
-
#import "ENRMLinkPillAttachment.h"
|
|
5
|
-
#import "LastElementUtils.h"
|
|
6
|
-
#import <React/RCTI18nUtil.h>
|
|
7
|
-
|
|
8
|
-
#if ENRICHED_TIPTAP_MATH
|
|
9
|
-
#import "ENRMMathInlineAttachment.h"
|
|
10
|
-
#endif
|
|
11
|
-
|
|
12
|
-
NSAttributedString *kNewlineAttributedString;
|
|
13
|
-
static NSParagraphStyle *kBlockSpacerTemplate;
|
|
14
|
-
|
|
15
|
-
NSLineBreakStrategy ENRMResolveLineBreakStrategy(NSString *strategy)
|
|
16
|
-
{
|
|
17
|
-
if ([strategy isEqualToString:@"standard"]) {
|
|
18
|
-
return NSLineBreakStrategyStandard;
|
|
19
|
-
} else if ([strategy isEqualToString:@"hangul-word"]) {
|
|
20
|
-
return NSLineBreakStrategyHangulWordPriority;
|
|
21
|
-
} else if ([strategy isEqualToString:@"push-out"]) {
|
|
22
|
-
return NSLineBreakStrategyPushOut;
|
|
23
|
-
}
|
|
24
|
-
return NSLineBreakStrategyNone;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
NSLineBreakMode ENRMResolveEllipsizeLineBreakMode(NSString *mode)
|
|
28
|
-
{
|
|
29
|
-
if ([mode isEqualToString:@"head"]) {
|
|
30
|
-
return NSLineBreakByTruncatingHead;
|
|
31
|
-
} else if ([mode isEqualToString:@"middle"]) {
|
|
32
|
-
return NSLineBreakByTruncatingMiddle;
|
|
33
|
-
} else if ([mode isEqualToString:@"clip"]) {
|
|
34
|
-
return NSLineBreakByClipping;
|
|
35
|
-
}
|
|
36
|
-
return NSLineBreakByTruncatingTail;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
__attribute__((constructor)) static void initParagraphStyleUtils(void)
|
|
40
|
-
{
|
|
41
|
-
kNewlineAttributedString = [[NSAttributedString alloc] initWithString:@"\n"];
|
|
42
|
-
|
|
43
|
-
NSMutableParagraphStyle *template = [[NSMutableParagraphStyle alloc] init];
|
|
44
|
-
template.minimumLineHeight = 1;
|
|
45
|
-
template.maximumLineHeight = 1;
|
|
46
|
-
kBlockSpacerTemplate = [template copy];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
ENRMWritingDirectionMode ENRMResolveWritingDirectionMode(NSString *value)
|
|
50
|
-
{
|
|
51
|
-
if ([value isEqualToString:@"ltr"]) {
|
|
52
|
-
return ENRMWritingDirectionModeLTR;
|
|
53
|
-
}
|
|
54
|
-
if ([value isEqualToString:@"rtl"]) {
|
|
55
|
-
return ENRMWritingDirectionModeRTL;
|
|
56
|
-
}
|
|
57
|
-
if ([value isEqualToString:@"auto"]) {
|
|
58
|
-
return ENRMWritingDirectionModeAuto;
|
|
59
|
-
}
|
|
60
|
-
return ENRMWritingDirectionModeFirstStrong;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static BOOL ENRMIsStrongRTLChar(unichar c)
|
|
64
|
-
{
|
|
65
|
-
return (c >= 0x0590 && c <= 0x08FF) || (c >= 0xFB1D && c <= 0xFDFF) || (c >= 0xFE70 && c <= 0xFEFF);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
NSWritingDirection ENRMFirstStrongDirection(NSString *text)
|
|
69
|
-
{
|
|
70
|
-
NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
|
|
71
|
-
NSUInteger length = text.length;
|
|
72
|
-
for (NSUInteger i = 0; i < length; i++) {
|
|
73
|
-
unichar c = [text characterAtIndex:i];
|
|
74
|
-
if (![letters characterIsMember:c]) {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
return ENRMIsStrongRTLChar(c) ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
|
|
78
|
-
}
|
|
79
|
-
return NSWritingDirectionNatural;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
BOOL ENRMParagraphIsRTL(NSParagraphStyle *style)
|
|
83
|
-
{
|
|
84
|
-
if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
|
|
85
|
-
return style.baseWritingDirection == NSWritingDirectionRightToLeft;
|
|
86
|
-
}
|
|
87
|
-
return [[RCTI18nUtil sharedInstance] isRTL];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
void ENRMApplyWritingDirectionMode(NSMutableAttributedString *output, ENRMWritingDirectionMode mode,
|
|
91
|
-
NSWritingDirection layoutDirection)
|
|
92
|
-
{
|
|
93
|
-
switch (mode) {
|
|
94
|
-
case ENRMWritingDirectionModeAuto:
|
|
95
|
-
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionNatural);
|
|
96
|
-
break;
|
|
97
|
-
case ENRMWritingDirectionModeLTR:
|
|
98
|
-
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionLeftToRight);
|
|
99
|
-
break;
|
|
100
|
-
case ENRMWritingDirectionModeRTL:
|
|
101
|
-
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionRightToLeft);
|
|
102
|
-
break;
|
|
103
|
-
case ENRMWritingDirectionModeFirstStrong:
|
|
104
|
-
ENRMApplyFirstStrongParagraphDirections(output, layoutDirection);
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
void ENRMApplyFirstStrongParagraphDirections(NSMutableAttributedString *output, NSWritingDirection fallback)
|
|
110
|
-
{
|
|
111
|
-
if (output.length == 0) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
NSString *string = output.string;
|
|
115
|
-
NSUInteger length = string.length;
|
|
116
|
-
NSUInteger position = 0;
|
|
117
|
-
while (position < length) {
|
|
118
|
-
NSRange paragraphRange = [string paragraphRangeForRange:NSMakeRange(position, 0)];
|
|
119
|
-
if (NSMaxRange(paragraphRange) <= position) {
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
position = NSMaxRange(paragraphRange);
|
|
123
|
-
|
|
124
|
-
NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
|
|
125
|
-
atIndex:paragraphRange.location
|
|
126
|
-
effectiveRange:nil];
|
|
127
|
-
if (isCodeBlock.boolValue) {
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
NSWritingDirection direction = ENRMFirstStrongDirection([string substringWithRange:paragraphRange]);
|
|
132
|
-
if (direction == NSWritingDirectionNatural) {
|
|
133
|
-
direction = fallback;
|
|
134
|
-
}
|
|
135
|
-
if (direction == NSWritingDirectionNatural) {
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
140
|
-
inRange:paragraphRange
|
|
141
|
-
options:0
|
|
142
|
-
usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
|
|
143
|
-
if (style != nil && style.baseWritingDirection == direction) {
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
NSMutableParagraphStyle *updated =
|
|
147
|
-
style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
|
|
148
|
-
updated.baseWritingDirection = direction;
|
|
149
|
-
[output addAttribute:NSParagraphStyleAttributeName value:updated range:range];
|
|
150
|
-
}];
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
void ENRMApplyWritingDirectionToParagraphStyles(NSMutableAttributedString *output, NSWritingDirection writingDirection)
|
|
155
|
-
{
|
|
156
|
-
if (output.length == 0) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
160
|
-
inRange:NSMakeRange(0, output.length)
|
|
161
|
-
options:0
|
|
162
|
-
usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
|
|
163
|
-
if (!style) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
// Skip runs already in the target direction (issue #739),
|
|
167
|
-
// mirroring ENRMApplyFirstStrongParagraphDirections.
|
|
168
|
-
if (style.baseWritingDirection == writingDirection) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
|
|
172
|
-
atIndex:range.location
|
|
173
|
-
effectiveRange:nil];
|
|
174
|
-
if (isCodeBlock.boolValue) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
NSMutableParagraphStyle *mutable = [style mutableCopy];
|
|
178
|
-
mutable.baseWritingDirection = writingDirection;
|
|
179
|
-
[output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
|
|
180
|
-
}];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
NSMutableParagraphStyle *getOrCreateParagraphStyle(NSMutableAttributedString *output, NSUInteger index)
|
|
184
|
-
{
|
|
185
|
-
NSParagraphStyle *existing = [output attribute:NSParagraphStyleAttributeName atIndex:index effectiveRange:NULL];
|
|
186
|
-
NSMutableParagraphStyle *style = existing ? [existing mutableCopy] : [[NSMutableParagraphStyle alloc] init];
|
|
187
|
-
return style;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
void applyParagraphSpacingAfter(NSMutableAttributedString *output, NSUInteger start, CGFloat marginBottom)
|
|
191
|
-
{
|
|
192
|
-
[output appendAttributedString:kNewlineAttributedString];
|
|
193
|
-
|
|
194
|
-
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, start);
|
|
195
|
-
style.paragraphSpacing = marginBottom;
|
|
196
|
-
|
|
197
|
-
NSRange range = NSMakeRange(start, output.length - start);
|
|
198
|
-
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
NSUInteger applyParagraphSpacingBefore(NSMutableAttributedString *output, NSRange range, CGFloat marginTop)
|
|
202
|
-
{
|
|
203
|
-
if (marginTop <= 0 || range.location == 0)
|
|
204
|
-
return 0;
|
|
205
|
-
|
|
206
|
-
NSUInteger prevIdx = range.location - 1;
|
|
207
|
-
if ([output.string characterAtIndex:prevIdx] != '\n')
|
|
208
|
-
return 0;
|
|
209
|
-
|
|
210
|
-
NSParagraphStyle *prevStyle = [output attribute:NSParagraphStyleAttributeName atIndex:prevIdx effectiveRange:NULL];
|
|
211
|
-
|
|
212
|
-
CGFloat prevMarginBottom = prevStyle.paragraphSpacing;
|
|
213
|
-
if (prevMarginBottom >= marginTop)
|
|
214
|
-
return 0;
|
|
215
|
-
|
|
216
|
-
CGFloat extraGap = marginTop - prevMarginBottom;
|
|
217
|
-
|
|
218
|
-
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
219
|
-
spacerStyle.paragraphSpacing = MAX(0, extraGap - 1.0);
|
|
220
|
-
|
|
221
|
-
NSDictionary *attrs = @{NSParagraphStyleAttributeName : spacerStyle};
|
|
222
|
-
NSAttributedString *spacer = [[NSAttributedString alloc] initWithString:@"\n" attributes:attrs];
|
|
223
|
-
|
|
224
|
-
[output insertAttributedString:spacer atIndex:range.location];
|
|
225
|
-
return 1;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
NSUInteger applyBlockSpacingBefore(NSMutableAttributedString *output, NSUInteger insertionPoint, CGFloat marginTop)
|
|
229
|
-
{
|
|
230
|
-
if (marginTop <= 0) {
|
|
231
|
-
return 0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
CGFloat spacing = marginTop;
|
|
235
|
-
|
|
236
|
-
// At index 0 the spacer \n produces a 1pt line fragment (minimumLineHeight=1)
|
|
237
|
-
// on top of paragraphSpacing. Subtract it so the total equals the desired margin.
|
|
238
|
-
// For non-zero positions the 1pt is intentional inter-block spacing.
|
|
239
|
-
if (insertionPoint == 0) {
|
|
240
|
-
spacing = MAX(0, marginTop - 1.0);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
244
|
-
spacerStyle.paragraphSpacing = spacing;
|
|
245
|
-
|
|
246
|
-
NSAttributedString *spacer =
|
|
247
|
-
[[NSAttributedString alloc] initWithString:@"\n" attributes:@{NSParagraphStyleAttributeName : spacerStyle}];
|
|
248
|
-
|
|
249
|
-
[output insertAttributedString:spacer atIndex:insertionPoint];
|
|
250
|
-
return 1;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBottom)
|
|
254
|
-
{
|
|
255
|
-
if (marginBottom <= 0) {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
NSUInteger spacerLocation = output.length;
|
|
260
|
-
[output appendAttributedString:kNewlineAttributedString];
|
|
261
|
-
|
|
262
|
-
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
263
|
-
spacerStyle.paragraphSpacing = marginBottom;
|
|
264
|
-
|
|
265
|
-
[output addAttribute:NSParagraphStyleAttributeName value:spacerStyle range:NSMakeRange(spacerLocation, 1)];
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
CGFloat ENRMLineHeightWithLinkPills(NSAttributedString *text, NSRange range, CGFloat lineHeight)
|
|
269
|
-
{
|
|
270
|
-
#if !TARGET_OS_OSX
|
|
271
|
-
__block CGFloat fitting = lineHeight;
|
|
272
|
-
[text enumerateAttribute:NSAttachmentAttributeName
|
|
273
|
-
inRange:range
|
|
274
|
-
options:0
|
|
275
|
-
usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
|
|
276
|
-
if ([value isKindOfClass:ENRMLinkPillAttachment.class])
|
|
277
|
-
fitting = MAX(fitting, ((ENRMLinkPillAttachment *)value).lineHeight);
|
|
278
|
-
}];
|
|
279
|
-
return fitting;
|
|
280
|
-
#else
|
|
281
|
-
return lineHeight;
|
|
282
|
-
#endif
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// UIKit's own key for the pre-substitution font. Not exported by any SDK header, so it is spelled out
|
|
286
|
-
// here; it is the same string UIKit writes into a UITextView's storage when it substitutes a font.
|
|
287
|
-
static NSString *const ENRMOriginalFontAttributeName = @"NSOriginalFont";
|
|
288
|
-
|
|
289
|
-
void ENRMPinLineMetricsToStyledFonts(NSMutableAttributedString *output, NSRange range)
|
|
290
|
-
{
|
|
291
|
-
if (range.length == 0 || NSMaxRange(range) > output.length) {
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
[output enumerateAttribute:NSFontAttributeName
|
|
296
|
-
inRange:range
|
|
297
|
-
options:0
|
|
298
|
-
usingBlock:^(UIFont *font, NSRange fontRange, __unused BOOL *stop) {
|
|
299
|
-
if (font) {
|
|
300
|
-
[output addAttribute:ENRMOriginalFontAttributeName value:font range:fontRange];
|
|
301
|
-
}
|
|
302
|
-
}];
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Floor, not clamp: minimumLineHeight keeps short lines at lineHeight, while maximumLineHeight = 0 lets
|
|
306
|
-
// a line grow to fit a taller run (large inline code, math, images) instead of clipping it.
|
|
307
|
-
// We can diverge from RN's clamp because we measure the real laid-out height, so grown lines are reserved.
|
|
308
|
-
void ENRMApplyLineHeightToParagraphStyle(NSMutableParagraphStyle *style, CGFloat lineHeight)
|
|
309
|
-
{
|
|
310
|
-
if (lineHeight <= 0) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
style.minimumLineHeight = lineHeight;
|
|
315
|
-
style.maximumLineHeight = 0;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight)
|
|
319
|
-
{
|
|
320
|
-
lineHeight = ENRMLineHeightWithLinkPills(output, range, lineHeight);
|
|
321
|
-
if (lineHeight <= 0) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
|
|
326
|
-
ENRMApplyLineHeightToParagraphStyle(style, lineHeight);
|
|
327
|
-
|
|
328
|
-
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Calculates the offset needed to center the text within the line height. Returns 0
|
|
332
|
-
// when the range has no minimum line height or its content already fills the line.
|
|
333
|
-
CGFloat calculateBaselineOffset(NSAttributedString *output, NSRange range)
|
|
334
|
-
{
|
|
335
|
-
if (range.length == 0) {
|
|
336
|
-
return 0;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// applyLineHeight floors lines with minimumLineHeight (maximumLineHeight is 0 for grown lines,
|
|
340
|
-
// or equal to the minimum for re-clamped code blocks), so the target is the minimum line height.
|
|
341
|
-
__block CGFloat targetLineHeight = 0;
|
|
342
|
-
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
343
|
-
inRange:range
|
|
344
|
-
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
|
345
|
-
usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange subrange, __unused BOOL *stop) {
|
|
346
|
-
if (!paragraphStyle) {
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
targetLineHeight = MAX(paragraphStyle.minimumLineHeight, targetLineHeight);
|
|
350
|
-
}];
|
|
351
|
-
|
|
352
|
-
if (targetLineHeight <= 0) {
|
|
353
|
-
return 0;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Center on real text; on a math-only line center the math box instead of its font.
|
|
357
|
-
__block CGFloat textLineHeight = 0;
|
|
358
|
-
#if ENRICHED_TIPTAP_MATH
|
|
359
|
-
__block BOOL hasMath = NO;
|
|
360
|
-
#endif
|
|
361
|
-
[output enumerateAttributesInRange:range
|
|
362
|
-
options:0
|
|
363
|
-
usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attrs, __unused NSRange subrange,
|
|
364
|
-
__unused BOOL *stop) {
|
|
365
|
-
#if ENRICHED_TIPTAP_MATH
|
|
366
|
-
if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) {
|
|
367
|
-
hasMath = YES;
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
#endif
|
|
371
|
-
UIFont *font = attrs[NSFontAttributeName];
|
|
372
|
-
if (font) {
|
|
373
|
-
textLineHeight = MAX(UIFontLineHeight(font), textLineHeight);
|
|
374
|
-
}
|
|
375
|
-
}];
|
|
376
|
-
|
|
377
|
-
CGFloat contentLineHeight = textLineHeight;
|
|
378
|
-
#if !TARGET_OS_OSX
|
|
379
|
-
__block CGFloat pillBoxHeight = 0;
|
|
380
|
-
[output enumerateAttribute:NSAttachmentAttributeName
|
|
381
|
-
inRange:range
|
|
382
|
-
options:0
|
|
383
|
-
usingBlock:^(id value, NSRange subrange, BOOL *stop) {
|
|
384
|
-
if ([value isKindOfClass:ENRMLinkPillAttachment.class])
|
|
385
|
-
pillBoxHeight = MAX(pillBoxHeight, ((ENRMLinkPillAttachment *)value).boxHeight);
|
|
386
|
-
}];
|
|
387
|
-
contentLineHeight = MAX(contentLineHeight, pillBoxHeight);
|
|
388
|
-
#endif
|
|
389
|
-
|
|
390
|
-
#if ENRICHED_TIPTAP_MATH
|
|
391
|
-
// Math only grows the content height, so measure it (parsing LaTeX) only when text
|
|
392
|
-
// alone wouldn't already fill the line.
|
|
393
|
-
if (hasMath && targetLineHeight > textLineHeight) {
|
|
394
|
-
__block CGFloat mathBoxHeight = 0;
|
|
395
|
-
[output enumerateAttribute:NSAttachmentAttributeName
|
|
396
|
-
inRange:range
|
|
397
|
-
options:0
|
|
398
|
-
usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
|
|
399
|
-
if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
|
|
400
|
-
mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight);
|
|
401
|
-
}
|
|
402
|
-
}];
|
|
403
|
-
contentLineHeight = MAX(contentLineHeight, mathBoxHeight);
|
|
404
|
-
}
|
|
405
|
-
#endif
|
|
406
|
-
|
|
407
|
-
if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) {
|
|
408
|
-
return 0;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return (targetLineHeight - contentLineHeight) / 2.0;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// Centers text within its line height (see calculateBaselineOffset). Called per block over its
|
|
415
|
-
// own range so blocks can keep different line heights. Ranges that already carry a baseline offset
|
|
416
|
-
// are left untouched, keeping nesting (e.g. a blockquote wrapping list items) idempotent.
|
|
417
|
-
void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
|
|
418
|
-
{
|
|
419
|
-
CGFloat baseLineOffset = calculateBaselineOffset(output, range);
|
|
420
|
-
if (baseLineOffset <= 0) {
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
[output enumerateAttribute:NSBaselineOffsetAttributeName
|
|
425
|
-
inRange:range
|
|
426
|
-
options:0
|
|
427
|
-
usingBlock:^(NSNumber *existingOffset, NSRange subrange, BOOL *stop) {
|
|
428
|
-
if (existingOffset != nil) {
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
[output enumerateAttribute:NSAttachmentAttributeName
|
|
432
|
-
inRange:subrange
|
|
433
|
-
options:0
|
|
434
|
-
usingBlock:^(id attachment, NSRange attachmentRange, BOOL *innerStop) {
|
|
435
|
-
if ([attachment isKindOfClass:[ENRMImageAttachment class]] &&
|
|
436
|
-
!((ENRMImageAttachment *)attachment).isInline) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
[output addAttribute:NSBaselineOffsetAttributeName
|
|
440
|
-
value:@(baseLineOffset)
|
|
441
|
-
range:attachmentRange];
|
|
442
|
-
}];
|
|
443
|
-
}];
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
void applyTextAlignment(NSMutableAttributedString *output, NSRange range, NSTextAlignment textAlign)
|
|
447
|
-
{
|
|
448
|
-
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
|
|
449
|
-
style.alignment = textAlign;
|
|
450
|
-
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
void ENRMApplyLineBreakStrategyToParagraphStyles(NSMutableAttributedString *output,
|
|
454
|
-
NSLineBreakStrategy lineBreakStrategy)
|
|
455
|
-
{
|
|
456
|
-
if (output.length == 0) {
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
460
|
-
inRange:NSMakeRange(0, output.length)
|
|
461
|
-
options:0
|
|
462
|
-
usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL *stop) {
|
|
463
|
-
if (!value) {
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
NSMutableParagraphStyle *mutable = [value mutableCopy];
|
|
467
|
-
mutable.lineBreakStrategy = lineBreakStrategy;
|
|
468
|
-
[output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
|
|
469
|
-
}];
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
NSTextAlignment textAlignmentFromString(NSString *textAlign)
|
|
473
|
-
{
|
|
474
|
-
if ([textAlign isEqualToString:@"left"]) {
|
|
475
|
-
return NSTextAlignmentLeft;
|
|
476
|
-
} else if ([textAlign isEqualToString:@"center"]) {
|
|
477
|
-
return NSTextAlignmentCenter;
|
|
478
|
-
} else if ([textAlign isEqualToString:@"right"]) {
|
|
479
|
-
return NSTextAlignmentRight;
|
|
480
|
-
} else if ([textAlign isEqualToString:@"justify"]) {
|
|
481
|
-
return NSTextAlignmentJustified;
|
|
482
|
-
}
|
|
483
|
-
return NSTextAlignmentNatural;
|
|
484
|
-
}
|
|
1
|
+
#import "ParagraphStyleUtils.h"
|
|
2
|
+
#import "ENRMFeatureFlags.h"
|
|
3
|
+
#import "ENRMImageAttachment.h"
|
|
4
|
+
#import "ENRMLinkPillAttachment.h"
|
|
5
|
+
#import "LastElementUtils.h"
|
|
6
|
+
#import <React/RCTI18nUtil.h>
|
|
7
|
+
|
|
8
|
+
#if ENRICHED_TIPTAP_MATH
|
|
9
|
+
#import "ENRMMathInlineAttachment.h"
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
NSAttributedString *kNewlineAttributedString;
|
|
13
|
+
static NSParagraphStyle *kBlockSpacerTemplate;
|
|
14
|
+
|
|
15
|
+
NSLineBreakStrategy ENRMResolveLineBreakStrategy(NSString *strategy)
|
|
16
|
+
{
|
|
17
|
+
if ([strategy isEqualToString:@"standard"]) {
|
|
18
|
+
return NSLineBreakStrategyStandard;
|
|
19
|
+
} else if ([strategy isEqualToString:@"hangul-word"]) {
|
|
20
|
+
return NSLineBreakStrategyHangulWordPriority;
|
|
21
|
+
} else if ([strategy isEqualToString:@"push-out"]) {
|
|
22
|
+
return NSLineBreakStrategyPushOut;
|
|
23
|
+
}
|
|
24
|
+
return NSLineBreakStrategyNone;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
NSLineBreakMode ENRMResolveEllipsizeLineBreakMode(NSString *mode)
|
|
28
|
+
{
|
|
29
|
+
if ([mode isEqualToString:@"head"]) {
|
|
30
|
+
return NSLineBreakByTruncatingHead;
|
|
31
|
+
} else if ([mode isEqualToString:@"middle"]) {
|
|
32
|
+
return NSLineBreakByTruncatingMiddle;
|
|
33
|
+
} else if ([mode isEqualToString:@"clip"]) {
|
|
34
|
+
return NSLineBreakByClipping;
|
|
35
|
+
}
|
|
36
|
+
return NSLineBreakByTruncatingTail;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
__attribute__((constructor)) static void initParagraphStyleUtils(void)
|
|
40
|
+
{
|
|
41
|
+
kNewlineAttributedString = [[NSAttributedString alloc] initWithString:@"\n"];
|
|
42
|
+
|
|
43
|
+
NSMutableParagraphStyle *template = [[NSMutableParagraphStyle alloc] init];
|
|
44
|
+
template.minimumLineHeight = 1;
|
|
45
|
+
template.maximumLineHeight = 1;
|
|
46
|
+
kBlockSpacerTemplate = [template copy];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ENRMWritingDirectionMode ENRMResolveWritingDirectionMode(NSString *value)
|
|
50
|
+
{
|
|
51
|
+
if ([value isEqualToString:@"ltr"]) {
|
|
52
|
+
return ENRMWritingDirectionModeLTR;
|
|
53
|
+
}
|
|
54
|
+
if ([value isEqualToString:@"rtl"]) {
|
|
55
|
+
return ENRMWritingDirectionModeRTL;
|
|
56
|
+
}
|
|
57
|
+
if ([value isEqualToString:@"auto"]) {
|
|
58
|
+
return ENRMWritingDirectionModeAuto;
|
|
59
|
+
}
|
|
60
|
+
return ENRMWritingDirectionModeFirstStrong;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static BOOL ENRMIsStrongRTLChar(unichar c)
|
|
64
|
+
{
|
|
65
|
+
return (c >= 0x0590 && c <= 0x08FF) || (c >= 0xFB1D && c <= 0xFDFF) || (c >= 0xFE70 && c <= 0xFEFF);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
NSWritingDirection ENRMFirstStrongDirection(NSString *text)
|
|
69
|
+
{
|
|
70
|
+
NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
|
|
71
|
+
NSUInteger length = text.length;
|
|
72
|
+
for (NSUInteger i = 0; i < length; i++) {
|
|
73
|
+
unichar c = [text characterAtIndex:i];
|
|
74
|
+
if (![letters characterIsMember:c]) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
return ENRMIsStrongRTLChar(c) ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
|
|
78
|
+
}
|
|
79
|
+
return NSWritingDirectionNatural;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
BOOL ENRMParagraphIsRTL(NSParagraphStyle *style)
|
|
83
|
+
{
|
|
84
|
+
if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
|
|
85
|
+
return style.baseWritingDirection == NSWritingDirectionRightToLeft;
|
|
86
|
+
}
|
|
87
|
+
return [[RCTI18nUtil sharedInstance] isRTL];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
void ENRMApplyWritingDirectionMode(NSMutableAttributedString *output, ENRMWritingDirectionMode mode,
|
|
91
|
+
NSWritingDirection layoutDirection)
|
|
92
|
+
{
|
|
93
|
+
switch (mode) {
|
|
94
|
+
case ENRMWritingDirectionModeAuto:
|
|
95
|
+
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionNatural);
|
|
96
|
+
break;
|
|
97
|
+
case ENRMWritingDirectionModeLTR:
|
|
98
|
+
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionLeftToRight);
|
|
99
|
+
break;
|
|
100
|
+
case ENRMWritingDirectionModeRTL:
|
|
101
|
+
ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionRightToLeft);
|
|
102
|
+
break;
|
|
103
|
+
case ENRMWritingDirectionModeFirstStrong:
|
|
104
|
+
ENRMApplyFirstStrongParagraphDirections(output, layoutDirection);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
void ENRMApplyFirstStrongParagraphDirections(NSMutableAttributedString *output, NSWritingDirection fallback)
|
|
110
|
+
{
|
|
111
|
+
if (output.length == 0) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
NSString *string = output.string;
|
|
115
|
+
NSUInteger length = string.length;
|
|
116
|
+
NSUInteger position = 0;
|
|
117
|
+
while (position < length) {
|
|
118
|
+
NSRange paragraphRange = [string paragraphRangeForRange:NSMakeRange(position, 0)];
|
|
119
|
+
if (NSMaxRange(paragraphRange) <= position) {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
position = NSMaxRange(paragraphRange);
|
|
123
|
+
|
|
124
|
+
NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
|
|
125
|
+
atIndex:paragraphRange.location
|
|
126
|
+
effectiveRange:nil];
|
|
127
|
+
if (isCodeBlock.boolValue) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
NSWritingDirection direction = ENRMFirstStrongDirection([string substringWithRange:paragraphRange]);
|
|
132
|
+
if (direction == NSWritingDirectionNatural) {
|
|
133
|
+
direction = fallback;
|
|
134
|
+
}
|
|
135
|
+
if (direction == NSWritingDirectionNatural) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
140
|
+
inRange:paragraphRange
|
|
141
|
+
options:0
|
|
142
|
+
usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
|
|
143
|
+
if (style != nil && style.baseWritingDirection == direction) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
NSMutableParagraphStyle *updated =
|
|
147
|
+
style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
|
|
148
|
+
updated.baseWritingDirection = direction;
|
|
149
|
+
[output addAttribute:NSParagraphStyleAttributeName value:updated range:range];
|
|
150
|
+
}];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
void ENRMApplyWritingDirectionToParagraphStyles(NSMutableAttributedString *output, NSWritingDirection writingDirection)
|
|
155
|
+
{
|
|
156
|
+
if (output.length == 0) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
160
|
+
inRange:NSMakeRange(0, output.length)
|
|
161
|
+
options:0
|
|
162
|
+
usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
|
|
163
|
+
if (!style) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Skip runs already in the target direction (issue #739),
|
|
167
|
+
// mirroring ENRMApplyFirstStrongParagraphDirections.
|
|
168
|
+
if (style.baseWritingDirection == writingDirection) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
|
|
172
|
+
atIndex:range.location
|
|
173
|
+
effectiveRange:nil];
|
|
174
|
+
if (isCodeBlock.boolValue) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
NSMutableParagraphStyle *mutable = [style mutableCopy];
|
|
178
|
+
mutable.baseWritingDirection = writingDirection;
|
|
179
|
+
[output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
|
|
180
|
+
}];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
NSMutableParagraphStyle *getOrCreateParagraphStyle(NSMutableAttributedString *output, NSUInteger index)
|
|
184
|
+
{
|
|
185
|
+
NSParagraphStyle *existing = [output attribute:NSParagraphStyleAttributeName atIndex:index effectiveRange:NULL];
|
|
186
|
+
NSMutableParagraphStyle *style = existing ? [existing mutableCopy] : [[NSMutableParagraphStyle alloc] init];
|
|
187
|
+
return style;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void applyParagraphSpacingAfter(NSMutableAttributedString *output, NSUInteger start, CGFloat marginBottom)
|
|
191
|
+
{
|
|
192
|
+
[output appendAttributedString:kNewlineAttributedString];
|
|
193
|
+
|
|
194
|
+
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, start);
|
|
195
|
+
style.paragraphSpacing = marginBottom;
|
|
196
|
+
|
|
197
|
+
NSRange range = NSMakeRange(start, output.length - start);
|
|
198
|
+
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
NSUInteger applyParagraphSpacingBefore(NSMutableAttributedString *output, NSRange range, CGFloat marginTop)
|
|
202
|
+
{
|
|
203
|
+
if (marginTop <= 0 || range.location == 0)
|
|
204
|
+
return 0;
|
|
205
|
+
|
|
206
|
+
NSUInteger prevIdx = range.location - 1;
|
|
207
|
+
if ([output.string characterAtIndex:prevIdx] != '\n')
|
|
208
|
+
return 0;
|
|
209
|
+
|
|
210
|
+
NSParagraphStyle *prevStyle = [output attribute:NSParagraphStyleAttributeName atIndex:prevIdx effectiveRange:NULL];
|
|
211
|
+
|
|
212
|
+
CGFloat prevMarginBottom = prevStyle.paragraphSpacing;
|
|
213
|
+
if (prevMarginBottom >= marginTop)
|
|
214
|
+
return 0;
|
|
215
|
+
|
|
216
|
+
CGFloat extraGap = marginTop - prevMarginBottom;
|
|
217
|
+
|
|
218
|
+
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
219
|
+
spacerStyle.paragraphSpacing = MAX(0, extraGap - 1.0);
|
|
220
|
+
|
|
221
|
+
NSDictionary *attrs = @{NSParagraphStyleAttributeName : spacerStyle};
|
|
222
|
+
NSAttributedString *spacer = [[NSAttributedString alloc] initWithString:@"\n" attributes:attrs];
|
|
223
|
+
|
|
224
|
+
[output insertAttributedString:spacer atIndex:range.location];
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
NSUInteger applyBlockSpacingBefore(NSMutableAttributedString *output, NSUInteger insertionPoint, CGFloat marginTop)
|
|
229
|
+
{
|
|
230
|
+
if (marginTop <= 0) {
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
CGFloat spacing = marginTop;
|
|
235
|
+
|
|
236
|
+
// At index 0 the spacer \n produces a 1pt line fragment (minimumLineHeight=1)
|
|
237
|
+
// on top of paragraphSpacing. Subtract it so the total equals the desired margin.
|
|
238
|
+
// For non-zero positions the 1pt is intentional inter-block spacing.
|
|
239
|
+
if (insertionPoint == 0) {
|
|
240
|
+
spacing = MAX(0, marginTop - 1.0);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
244
|
+
spacerStyle.paragraphSpacing = spacing;
|
|
245
|
+
|
|
246
|
+
NSAttributedString *spacer =
|
|
247
|
+
[[NSAttributedString alloc] initWithString:@"\n" attributes:@{NSParagraphStyleAttributeName : spacerStyle}];
|
|
248
|
+
|
|
249
|
+
[output insertAttributedString:spacer atIndex:insertionPoint];
|
|
250
|
+
return 1;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBottom)
|
|
254
|
+
{
|
|
255
|
+
if (marginBottom <= 0) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
NSUInteger spacerLocation = output.length;
|
|
260
|
+
[output appendAttributedString:kNewlineAttributedString];
|
|
261
|
+
|
|
262
|
+
NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
|
|
263
|
+
spacerStyle.paragraphSpacing = marginBottom;
|
|
264
|
+
|
|
265
|
+
[output addAttribute:NSParagraphStyleAttributeName value:spacerStyle range:NSMakeRange(spacerLocation, 1)];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
CGFloat ENRMLineHeightWithLinkPills(NSAttributedString *text, NSRange range, CGFloat lineHeight)
|
|
269
|
+
{
|
|
270
|
+
#if !TARGET_OS_OSX
|
|
271
|
+
__block CGFloat fitting = lineHeight;
|
|
272
|
+
[text enumerateAttribute:NSAttachmentAttributeName
|
|
273
|
+
inRange:range
|
|
274
|
+
options:0
|
|
275
|
+
usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
|
|
276
|
+
if ([value isKindOfClass:ENRMLinkPillAttachment.class])
|
|
277
|
+
fitting = MAX(fitting, ((ENRMLinkPillAttachment *)value).lineHeight);
|
|
278
|
+
}];
|
|
279
|
+
return fitting;
|
|
280
|
+
#else
|
|
281
|
+
return lineHeight;
|
|
282
|
+
#endif
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// UIKit's own key for the pre-substitution font. Not exported by any SDK header, so it is spelled out
|
|
286
|
+
// here; it is the same string UIKit writes into a UITextView's storage when it substitutes a font.
|
|
287
|
+
static NSString *const ENRMOriginalFontAttributeName = @"NSOriginalFont";
|
|
288
|
+
|
|
289
|
+
void ENRMPinLineMetricsToStyledFonts(NSMutableAttributedString *output, NSRange range)
|
|
290
|
+
{
|
|
291
|
+
if (range.length == 0 || NSMaxRange(range) > output.length) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
[output enumerateAttribute:NSFontAttributeName
|
|
296
|
+
inRange:range
|
|
297
|
+
options:0
|
|
298
|
+
usingBlock:^(UIFont *font, NSRange fontRange, __unused BOOL *stop) {
|
|
299
|
+
if (font) {
|
|
300
|
+
[output addAttribute:ENRMOriginalFontAttributeName value:font range:fontRange];
|
|
301
|
+
}
|
|
302
|
+
}];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Floor, not clamp: minimumLineHeight keeps short lines at lineHeight, while maximumLineHeight = 0 lets
|
|
306
|
+
// a line grow to fit a taller run (large inline code, math, images) instead of clipping it.
|
|
307
|
+
// We can diverge from RN's clamp because we measure the real laid-out height, so grown lines are reserved.
|
|
308
|
+
void ENRMApplyLineHeightToParagraphStyle(NSMutableParagraphStyle *style, CGFloat lineHeight)
|
|
309
|
+
{
|
|
310
|
+
if (lineHeight <= 0) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
style.minimumLineHeight = lineHeight;
|
|
315
|
+
style.maximumLineHeight = 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight)
|
|
319
|
+
{
|
|
320
|
+
lineHeight = ENRMLineHeightWithLinkPills(output, range, lineHeight);
|
|
321
|
+
if (lineHeight <= 0) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
|
|
326
|
+
ENRMApplyLineHeightToParagraphStyle(style, lineHeight);
|
|
327
|
+
|
|
328
|
+
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Calculates the offset needed to center the text within the line height. Returns 0
|
|
332
|
+
// when the range has no minimum line height or its content already fills the line.
|
|
333
|
+
CGFloat calculateBaselineOffset(NSAttributedString *output, NSRange range)
|
|
334
|
+
{
|
|
335
|
+
if (range.length == 0) {
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// applyLineHeight floors lines with minimumLineHeight (maximumLineHeight is 0 for grown lines,
|
|
340
|
+
// or equal to the minimum for re-clamped code blocks), so the target is the minimum line height.
|
|
341
|
+
__block CGFloat targetLineHeight = 0;
|
|
342
|
+
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
343
|
+
inRange:range
|
|
344
|
+
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
|
|
345
|
+
usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange subrange, __unused BOOL *stop) {
|
|
346
|
+
if (!paragraphStyle) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
targetLineHeight = MAX(paragraphStyle.minimumLineHeight, targetLineHeight);
|
|
350
|
+
}];
|
|
351
|
+
|
|
352
|
+
if (targetLineHeight <= 0) {
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Center on real text; on a math-only line center the math box instead of its font.
|
|
357
|
+
__block CGFloat textLineHeight = 0;
|
|
358
|
+
#if ENRICHED_TIPTAP_MATH
|
|
359
|
+
__block BOOL hasMath = NO;
|
|
360
|
+
#endif
|
|
361
|
+
[output enumerateAttributesInRange:range
|
|
362
|
+
options:0
|
|
363
|
+
usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attrs, __unused NSRange subrange,
|
|
364
|
+
__unused BOOL *stop) {
|
|
365
|
+
#if ENRICHED_TIPTAP_MATH
|
|
366
|
+
if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) {
|
|
367
|
+
hasMath = YES;
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
#endif
|
|
371
|
+
UIFont *font = attrs[NSFontAttributeName];
|
|
372
|
+
if (font) {
|
|
373
|
+
textLineHeight = MAX(UIFontLineHeight(font), textLineHeight);
|
|
374
|
+
}
|
|
375
|
+
}];
|
|
376
|
+
|
|
377
|
+
CGFloat contentLineHeight = textLineHeight;
|
|
378
|
+
#if !TARGET_OS_OSX
|
|
379
|
+
__block CGFloat pillBoxHeight = 0;
|
|
380
|
+
[output enumerateAttribute:NSAttachmentAttributeName
|
|
381
|
+
inRange:range
|
|
382
|
+
options:0
|
|
383
|
+
usingBlock:^(id value, NSRange subrange, BOOL *stop) {
|
|
384
|
+
if ([value isKindOfClass:ENRMLinkPillAttachment.class])
|
|
385
|
+
pillBoxHeight = MAX(pillBoxHeight, ((ENRMLinkPillAttachment *)value).boxHeight);
|
|
386
|
+
}];
|
|
387
|
+
contentLineHeight = MAX(contentLineHeight, pillBoxHeight);
|
|
388
|
+
#endif
|
|
389
|
+
|
|
390
|
+
#if ENRICHED_TIPTAP_MATH
|
|
391
|
+
// Math only grows the content height, so measure it (parsing LaTeX) only when text
|
|
392
|
+
// alone wouldn't already fill the line.
|
|
393
|
+
if (hasMath && targetLineHeight > textLineHeight) {
|
|
394
|
+
__block CGFloat mathBoxHeight = 0;
|
|
395
|
+
[output enumerateAttribute:NSAttachmentAttributeName
|
|
396
|
+
inRange:range
|
|
397
|
+
options:0
|
|
398
|
+
usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
|
|
399
|
+
if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
|
|
400
|
+
mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight);
|
|
401
|
+
}
|
|
402
|
+
}];
|
|
403
|
+
contentLineHeight = MAX(contentLineHeight, mathBoxHeight);
|
|
404
|
+
}
|
|
405
|
+
#endif
|
|
406
|
+
|
|
407
|
+
if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) {
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return (targetLineHeight - contentLineHeight) / 2.0;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Centers text within its line height (see calculateBaselineOffset). Called per block over its
|
|
415
|
+
// own range so blocks can keep different line heights. Ranges that already carry a baseline offset
|
|
416
|
+
// are left untouched, keeping nesting (e.g. a blockquote wrapping list items) idempotent.
|
|
417
|
+
void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
|
|
418
|
+
{
|
|
419
|
+
CGFloat baseLineOffset = calculateBaselineOffset(output, range);
|
|
420
|
+
if (baseLineOffset <= 0) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
[output enumerateAttribute:NSBaselineOffsetAttributeName
|
|
425
|
+
inRange:range
|
|
426
|
+
options:0
|
|
427
|
+
usingBlock:^(NSNumber *existingOffset, NSRange subrange, BOOL *stop) {
|
|
428
|
+
if (existingOffset != nil) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
[output enumerateAttribute:NSAttachmentAttributeName
|
|
432
|
+
inRange:subrange
|
|
433
|
+
options:0
|
|
434
|
+
usingBlock:^(id attachment, NSRange attachmentRange, BOOL *innerStop) {
|
|
435
|
+
if ([attachment isKindOfClass:[ENRMImageAttachment class]] &&
|
|
436
|
+
!((ENRMImageAttachment *)attachment).isInline) {
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
[output addAttribute:NSBaselineOffsetAttributeName
|
|
440
|
+
value:@(baseLineOffset)
|
|
441
|
+
range:attachmentRange];
|
|
442
|
+
}];
|
|
443
|
+
}];
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
void applyTextAlignment(NSMutableAttributedString *output, NSRange range, NSTextAlignment textAlign)
|
|
447
|
+
{
|
|
448
|
+
NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
|
|
449
|
+
style.alignment = textAlign;
|
|
450
|
+
[output addAttribute:NSParagraphStyleAttributeName value:style range:range];
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
void ENRMApplyLineBreakStrategyToParagraphStyles(NSMutableAttributedString *output,
|
|
454
|
+
NSLineBreakStrategy lineBreakStrategy)
|
|
455
|
+
{
|
|
456
|
+
if (output.length == 0) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
[output enumerateAttribute:NSParagraphStyleAttributeName
|
|
460
|
+
inRange:NSMakeRange(0, output.length)
|
|
461
|
+
options:0
|
|
462
|
+
usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL *stop) {
|
|
463
|
+
if (!value) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
NSMutableParagraphStyle *mutable = [value mutableCopy];
|
|
467
|
+
mutable.lineBreakStrategy = lineBreakStrategy;
|
|
468
|
+
[output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
|
|
469
|
+
}];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
NSTextAlignment textAlignmentFromString(NSString *textAlign)
|
|
473
|
+
{
|
|
474
|
+
if ([textAlign isEqualToString:@"left"]) {
|
|
475
|
+
return NSTextAlignmentLeft;
|
|
476
|
+
} else if ([textAlign isEqualToString:@"center"]) {
|
|
477
|
+
return NSTextAlignmentCenter;
|
|
478
|
+
} else if ([textAlign isEqualToString:@"right"]) {
|
|
479
|
+
return NSTextAlignmentRight;
|
|
480
|
+
} else if ([textAlign isEqualToString:@"justify"]) {
|
|
481
|
+
return NSTextAlignmentJustified;
|
|
482
|
+
}
|
|
483
|
+
return NSTextAlignmentNatural;
|
|
484
|
+
}
|