@mathers101/react-native-render-rich-text 0.1.9 → 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,25 +1,25 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
#import "ENRMUIKit.h"
|
|
3
|
-
|
|
4
|
-
#import "ENRMLinkContextMenus.h"
|
|
5
|
-
|
|
6
|
-
#if !TARGET_OS_OSX
|
|
7
|
-
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* The read-only text view tiptap renders into. A link pill is one placeholder character
|
|
11
|
-
* in text storage; what the system reads for the selection (Look Up, Translate, Share,
|
|
12
|
-
* drag, the Copy key command) is answered here with the link text the pill stands for.
|
|
13
|
-
*
|
|
14
|
-
* It also presents the menu of a pill that has one, taken from a delegate that is an
|
|
15
|
-
* `ENRMLinkContextMenuSource`: UIKit lifts a pressed text item on a tinted box of its own,
|
|
16
|
-
* which hides the pill's look.
|
|
17
|
-
*/
|
|
18
|
-
@interface ENRMTiptapTextView : UITextView <ENRMLinkMenuPresenting>
|
|
19
|
-
/// Copies a selection the way the menu Copy does. Set by the hosting view, which knows the
|
|
20
|
-
/// source Tiptap and style; without it the Copy key command writes plain text and RTF only.
|
|
21
|
-
@property (nonatomic, copy, nullable) void (^copySelectionHandler)(NSRange selectedRange);
|
|
22
|
-
@end
|
|
23
|
-
|
|
24
|
-
NS_ASSUME_NONNULL_END
|
|
25
|
-
#endif
|
|
1
|
+
#pragma once
|
|
2
|
+
#import "ENRMUIKit.h"
|
|
3
|
+
|
|
4
|
+
#import "ENRMLinkContextMenus.h"
|
|
5
|
+
|
|
6
|
+
#if !TARGET_OS_OSX
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The read-only text view tiptap renders into. A link pill is one placeholder character
|
|
11
|
+
* in text storage; what the system reads for the selection (Look Up, Translate, Share,
|
|
12
|
+
* drag, the Copy key command) is answered here with the link text the pill stands for.
|
|
13
|
+
*
|
|
14
|
+
* It also presents the menu of a pill that has one, taken from a delegate that is an
|
|
15
|
+
* `ENRMLinkContextMenuSource`: UIKit lifts a pressed text item on a tinted box of its own,
|
|
16
|
+
* which hides the pill's look.
|
|
17
|
+
*/
|
|
18
|
+
@interface ENRMTiptapTextView : UITextView <ENRMLinkMenuPresenting>
|
|
19
|
+
/// Copies a selection the way the menu Copy does. Set by the hosting view, which knows the
|
|
20
|
+
/// source Tiptap and style; without it the Copy key command writes plain text and RTF only.
|
|
21
|
+
@property (nonatomic, copy, nullable) void (^copySelectionHandler)(NSRange selectedRange);
|
|
22
|
+
@end
|
|
23
|
+
|
|
24
|
+
NS_ASSUME_NONNULL_END
|
|
25
|
+
#endif
|
|
@@ -1,247 +1,247 @@
|
|
|
1
|
-
#import "ENRMTiptapTextView.h"
|
|
2
|
-
#import "ENRMLinkPillAttachment.h"
|
|
3
|
-
#import "ENRMLinkPillText.h"
|
|
4
|
-
#import "ENRMTextHitTest.h"
|
|
5
|
-
#import "LinkTapUtils.h"
|
|
6
|
-
#import "PasteboardUtils.h"
|
|
7
|
-
|
|
8
|
-
#if !TARGET_OS_OSX
|
|
9
|
-
@interface ENRMTiptapTextView () <UIContextMenuInteractionDelegate>
|
|
10
|
-
@end
|
|
11
|
-
|
|
12
|
-
@implementation ENRMTiptapTextView {
|
|
13
|
-
ENRMLinkMenuLift *_pillLift;
|
|
14
|
-
// The pill whose menu is being presented. It draws nothing for as long as its lifted image
|
|
15
|
-
// stands in for it: it would show through that image.
|
|
16
|
-
ENRMLinkPillAttachment *_liftedPill;
|
|
17
|
-
NSUInteger _pillMenuIndex;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer
|
|
21
|
-
{
|
|
22
|
-
if (self = [super initWithFrame:frame textContainer:textContainer]) {
|
|
23
|
-
_pillLift = [[ENRMLinkMenuLift alloc] init];
|
|
24
|
-
__weak ENRMTiptapTextView *weakSelf = self;
|
|
25
|
-
_pillLift.onEnd = ^{ [weakSelf restoreLiftedPill]; };
|
|
26
|
-
[self addInteraction:[[UIContextMenuInteraction alloc] initWithDelegate:self]];
|
|
27
|
-
}
|
|
28
|
-
return self;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/// A tap places the caret, and UITextView then scrolls that caret into view. This view is
|
|
32
|
-
/// already sized to its text and sits in the screen's scroll view, so that scroll shifts
|
|
33
|
-
/// the page and the tapped line jumps toward the top. Scrolling stays off, and these
|
|
34
|
-
/// requests are dropped. Copy and selection are unchanged.
|
|
35
|
-
- (void)setContentOffset:(CGPoint)contentOffset
|
|
36
|
-
{
|
|
37
|
-
if (!self.scrollEnabled && !CGPointEqualToPoint(contentOffset, CGPointZero)) {
|
|
38
|
-
if (!CGPointEqualToPoint(self.contentOffset, CGPointZero)) {
|
|
39
|
-
[super setContentOffset:CGPointZero];
|
|
40
|
-
}
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
[super setContentOffset:contentOffset];
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
|
|
47
|
-
{
|
|
48
|
-
if (!self.scrollEnabled) {
|
|
49
|
-
[self setContentOffset:CGPointZero];
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
[super setContentOffset:contentOffset animated:animated];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
- (void)scrollRangeToVisible:(NSRange)range
|
|
56
|
-
{
|
|
57
|
-
if (self.scrollEnabled)
|
|
58
|
-
[super scrollRangeToVisible:range];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
|
|
62
|
-
{
|
|
63
|
-
if (self.scrollEnabled)
|
|
64
|
-
[super scrollRectToVisible:rect animated:animated];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/// New text moves or replaces the pill under its lifted image.
|
|
68
|
-
- (void)setAttributedText:(NSAttributedString *)attributedText
|
|
69
|
-
{
|
|
70
|
-
[_pillLift end];
|
|
71
|
-
[super setAttributedText:attributedText];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/// The selection with pills expanded, or nil when `range` is not the selection or holds no pill.
|
|
75
|
-
/// Only the selection is rewritten: UIKit also reads arbitrary ranges to find word boundaries,
|
|
76
|
-
/// and those must keep matching storage offsets.
|
|
77
|
-
- (nullable NSAttributedString *)expandedSelectionForRange:(UITextRange *)range
|
|
78
|
-
{
|
|
79
|
-
UITextRange *selection = self.selectedTextRange;
|
|
80
|
-
if (!range || !selection || selection.isEmpty || ![range isEqual:selection])
|
|
81
|
-
return nil;
|
|
82
|
-
NSRange selected = self.selectedRange;
|
|
83
|
-
NSTextStorage *storage = self.textStorage;
|
|
84
|
-
if (selected.location == NSNotFound || NSMaxRange(selected) > storage.length)
|
|
85
|
-
return nil;
|
|
86
|
-
NSAttributedString *text = [storage attributedSubstringFromRange:selected];
|
|
87
|
-
NSAttributedString *expanded = ENRMAttributedStringByExpandingLinkPills(text, NULL);
|
|
88
|
-
return expanded == text ? nil : expanded;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
- (NSString *)textInRange:(UITextRange *)range
|
|
92
|
-
{
|
|
93
|
-
return [self expandedSelectionForRange:range].string ?: [super textInRange:range];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
- (NSAttributedString *)attributedTextInRange:(UITextRange *)range
|
|
97
|
-
{
|
|
98
|
-
return [self expandedSelectionForRange:range] ?: [super attributedTextInRange:range];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/// The menu's Copy is already replaced by the library's own action; this covers the key command.
|
|
102
|
-
- (void)copy:(id)sender
|
|
103
|
-
{
|
|
104
|
-
NSRange selected = self.selectedRange;
|
|
105
|
-
if (self.copySelectionHandler && selected.location != NSNotFound && selected.length > 0) {
|
|
106
|
-
self.copySelectionHandler(selected);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
NSAttributedString *expanded = [self expandedSelectionForRange:self.selectedTextRange];
|
|
110
|
-
if (!expanded) {
|
|
111
|
-
[super copy:sender];
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
copyAttributedStringToPasteboard(expanded, nil, nil);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
#pragma mark - Pill menus
|
|
118
|
-
|
|
119
|
-
- (nullable ENRMLinkContextMenus *)linkContextMenus
|
|
120
|
-
{
|
|
121
|
-
id delegate = self.delegate;
|
|
122
|
-
return [delegate conformsToProtocol:@protocol(ENRMLinkContextMenuSource)]
|
|
123
|
-
? [(id<ENRMLinkContextMenuSource>)delegate linkContextMenusForTextView:self]
|
|
124
|
-
: nil;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/// Where the pill at `index` is drawn, in the text view's coordinates.
|
|
128
|
-
- (CGRect)pillFrameAtIndex:(NSUInteger)index
|
|
129
|
-
{
|
|
130
|
-
NSLayoutManager *layoutManager = self.layoutManager;
|
|
131
|
-
NSUInteger glyph = [layoutManager glyphIndexForCharacterAtIndex:index];
|
|
132
|
-
CGSize size = [layoutManager attachmentSizeForGlyphAtIndex:glyph];
|
|
133
|
-
if (size.width <= 0 || size.height <= 0)
|
|
134
|
-
return CGRectNull;
|
|
135
|
-
CGRect line = [layoutManager lineFragmentRectForGlyphAtIndex:glyph effectiveRange:NULL];
|
|
136
|
-
// TextKit places an attachment glyph at the bottom edge of its bounds.
|
|
137
|
-
CGPoint location = [layoutManager locationForGlyphAtIndex:glyph];
|
|
138
|
-
UIEdgeInsets inset = self.textContainerInset;
|
|
139
|
-
return CGRectMake(inset.left + line.origin.x + location.x, inset.top + line.origin.y + location.y - size.height,
|
|
140
|
-
size.width, size.height);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/// Whether the character at `index` is a pill whose link has a menu.
|
|
144
|
-
- (BOOL)presentsLinkMenuAtIndex:(NSUInteger)index
|
|
145
|
-
{
|
|
146
|
-
ENRMLinkContextMenus *menus = [self linkContextMenus];
|
|
147
|
-
NSTextStorage *storage = self.textStorage;
|
|
148
|
-
if (menus.entries.count == 0 || index >= storage.length)
|
|
149
|
-
return NO;
|
|
150
|
-
id attachment = [storage attribute:NSAttachmentAttributeName atIndex:index effectiveRange:NULL];
|
|
151
|
-
return [attachment isKindOfClass:ENRMLinkPillAttachment.class] &&
|
|
152
|
-
[menus hasMenuForURL:linkURLAtRange(self, NSMakeRange(index, 1))];
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/// The character index of the pill under `point` when its link has a menu, else NSNotFound.
|
|
156
|
-
- (NSUInteger)menuPillIndexAtPoint:(CGPoint)point
|
|
157
|
-
{
|
|
158
|
-
if ([self linkContextMenus].entries.count == 0)
|
|
159
|
-
return NSNotFound;
|
|
160
|
-
NSUInteger index = ENRMCharacterIndexAtPoint(self, point);
|
|
161
|
-
if (index == NSNotFound || ![self presentsLinkMenuAtIndex:index] ||
|
|
162
|
-
!CGRectContainsPoint([self pillFrameAtIndex:index], point))
|
|
163
|
-
return NSNotFound;
|
|
164
|
-
return index;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
- (void)setPill:(ENRMLinkPillAttachment *)pill lifted:(BOOL)lifted
|
|
168
|
-
{
|
|
169
|
-
pill.lifted = lifted;
|
|
170
|
-
NSTextStorage *storage = self.textStorage;
|
|
171
|
-
[storage enumerateAttribute:NSAttachmentAttributeName
|
|
172
|
-
inRange:NSMakeRange(0, storage.length)
|
|
173
|
-
options:0
|
|
174
|
-
usingBlock:^(id value, NSRange range, BOOL *stop) {
|
|
175
|
-
if (value != pill)
|
|
176
|
-
return;
|
|
177
|
-
[self.layoutManager invalidateDisplayForCharacterRange:range];
|
|
178
|
-
*stop = YES;
|
|
179
|
-
}];
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
- (void)restoreLiftedPill
|
|
183
|
-
{
|
|
184
|
-
if (_liftedPill)
|
|
185
|
-
[self setPill:_liftedPill lifted:NO];
|
|
186
|
-
_liftedPill = nil;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
190
|
-
configurationForMenuAtLocation:(CGPoint)location
|
|
191
|
-
{
|
|
192
|
-
[_pillLift end];
|
|
193
|
-
_pillMenuIndex = [self menuPillIndexAtPoint:location];
|
|
194
|
-
if (_pillMenuIndex == NSNotFound)
|
|
195
|
-
return nil;
|
|
196
|
-
UIMenu *menu = [[self linkContextMenus] menuForURL:linkURLAtRange(self, NSMakeRange(_pillMenuIndex, 1))
|
|
197
|
-
title:linkTitleAtIndex(self.textStorage, _pillMenuIndex)];
|
|
198
|
-
if (!menu)
|
|
199
|
-
return nil;
|
|
200
|
-
return [UIContextMenuConfiguration
|
|
201
|
-
configurationWithIdentifier:nil
|
|
202
|
-
previewProvider:nil
|
|
203
|
-
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) { return menu; }];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/// The pill is lifted as an image of itself, see `ENRMLinkMenuLift`.
|
|
207
|
-
- (UITargetedPreview *)pillMenuPreview
|
|
208
|
-
{
|
|
209
|
-
if (![_pillLift isOverView:self]) {
|
|
210
|
-
NSTextStorage *storage = self.textStorage;
|
|
211
|
-
if (self.window == nil || _pillMenuIndex >= storage.length)
|
|
212
|
-
return nil;
|
|
213
|
-
id attachment = [storage attribute:NSAttachmentAttributeName atIndex:_pillMenuIndex effectiveRange:NULL];
|
|
214
|
-
CGRect frame = [self pillFrameAtIndex:_pillMenuIndex];
|
|
215
|
-
if (![attachment isKindOfClass:ENRMLinkPillAttachment.class] || CGRectIsNull(frame))
|
|
216
|
-
return nil;
|
|
217
|
-
UIImage *image = [(ENRMLinkPillAttachment *)attachment imageForBounds:(CGRect){CGPointZero, frame.size}
|
|
218
|
-
textContainer:self.textContainer
|
|
219
|
-
characterIndex:_pillMenuIndex];
|
|
220
|
-
[_pillLift layImage:image atFrame:frame overView:self];
|
|
221
|
-
_liftedPill = attachment;
|
|
222
|
-
[self setPill:_liftedPill lifted:YES];
|
|
223
|
-
}
|
|
224
|
-
return [_pillLift previewWithCornerRadius:_liftedPill.cornerRadius backgroundColor:UIColor.clearColor];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
228
|
-
previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
|
|
229
|
-
{
|
|
230
|
-
return [self pillMenuPreview];
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
234
|
-
previewForDismissingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
|
|
235
|
-
{
|
|
236
|
-
return [self pillMenuPreview];
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
240
|
-
willEndForConfiguration:(UIContextMenuConfiguration *)configuration
|
|
241
|
-
animator:(id<UIContextMenuInteractionAnimating>)animator
|
|
242
|
-
{
|
|
243
|
-
[_pillLift endWithAnimator:animator];
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
@end
|
|
247
|
-
#endif
|
|
1
|
+
#import "ENRMTiptapTextView.h"
|
|
2
|
+
#import "ENRMLinkPillAttachment.h"
|
|
3
|
+
#import "ENRMLinkPillText.h"
|
|
4
|
+
#import "ENRMTextHitTest.h"
|
|
5
|
+
#import "LinkTapUtils.h"
|
|
6
|
+
#import "PasteboardUtils.h"
|
|
7
|
+
|
|
8
|
+
#if !TARGET_OS_OSX
|
|
9
|
+
@interface ENRMTiptapTextView () <UIContextMenuInteractionDelegate>
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
@implementation ENRMTiptapTextView {
|
|
13
|
+
ENRMLinkMenuLift *_pillLift;
|
|
14
|
+
// The pill whose menu is being presented. It draws nothing for as long as its lifted image
|
|
15
|
+
// stands in for it: it would show through that image.
|
|
16
|
+
ENRMLinkPillAttachment *_liftedPill;
|
|
17
|
+
NSUInteger _pillMenuIndex;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer
|
|
21
|
+
{
|
|
22
|
+
if (self = [super initWithFrame:frame textContainer:textContainer]) {
|
|
23
|
+
_pillLift = [[ENRMLinkMenuLift alloc] init];
|
|
24
|
+
__weak ENRMTiptapTextView *weakSelf = self;
|
|
25
|
+
_pillLift.onEnd = ^{ [weakSelf restoreLiftedPill]; };
|
|
26
|
+
[self addInteraction:[[UIContextMenuInteraction alloc] initWithDelegate:self]];
|
|
27
|
+
}
|
|
28
|
+
return self;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// A tap places the caret, and UITextView then scrolls that caret into view. This view is
|
|
32
|
+
/// already sized to its text and sits in the screen's scroll view, so that scroll shifts
|
|
33
|
+
/// the page and the tapped line jumps toward the top. Scrolling stays off, and these
|
|
34
|
+
/// requests are dropped. Copy and selection are unchanged.
|
|
35
|
+
- (void)setContentOffset:(CGPoint)contentOffset
|
|
36
|
+
{
|
|
37
|
+
if (!self.scrollEnabled && !CGPointEqualToPoint(contentOffset, CGPointZero)) {
|
|
38
|
+
if (!CGPointEqualToPoint(self.contentOffset, CGPointZero)) {
|
|
39
|
+
[super setContentOffset:CGPointZero];
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
[super setContentOffset:contentOffset];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated
|
|
47
|
+
{
|
|
48
|
+
if (!self.scrollEnabled) {
|
|
49
|
+
[self setContentOffset:CGPointZero];
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
[super setContentOffset:contentOffset animated:animated];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
- (void)scrollRangeToVisible:(NSRange)range
|
|
56
|
+
{
|
|
57
|
+
if (self.scrollEnabled)
|
|
58
|
+
[super scrollRangeToVisible:range];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
|
|
62
|
+
{
|
|
63
|
+
if (self.scrollEnabled)
|
|
64
|
+
[super scrollRectToVisible:rect animated:animated];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// New text moves or replaces the pill under its lifted image.
|
|
68
|
+
- (void)setAttributedText:(NSAttributedString *)attributedText
|
|
69
|
+
{
|
|
70
|
+
[_pillLift end];
|
|
71
|
+
[super setAttributedText:attributedText];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// The selection with pills expanded, or nil when `range` is not the selection or holds no pill.
|
|
75
|
+
/// Only the selection is rewritten: UIKit also reads arbitrary ranges to find word boundaries,
|
|
76
|
+
/// and those must keep matching storage offsets.
|
|
77
|
+
- (nullable NSAttributedString *)expandedSelectionForRange:(UITextRange *)range
|
|
78
|
+
{
|
|
79
|
+
UITextRange *selection = self.selectedTextRange;
|
|
80
|
+
if (!range || !selection || selection.isEmpty || ![range isEqual:selection])
|
|
81
|
+
return nil;
|
|
82
|
+
NSRange selected = self.selectedRange;
|
|
83
|
+
NSTextStorage *storage = self.textStorage;
|
|
84
|
+
if (selected.location == NSNotFound || NSMaxRange(selected) > storage.length)
|
|
85
|
+
return nil;
|
|
86
|
+
NSAttributedString *text = [storage attributedSubstringFromRange:selected];
|
|
87
|
+
NSAttributedString *expanded = ENRMAttributedStringByExpandingLinkPills(text, NULL);
|
|
88
|
+
return expanded == text ? nil : expanded;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
- (NSString *)textInRange:(UITextRange *)range
|
|
92
|
+
{
|
|
93
|
+
return [self expandedSelectionForRange:range].string ?: [super textInRange:range];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
- (NSAttributedString *)attributedTextInRange:(UITextRange *)range
|
|
97
|
+
{
|
|
98
|
+
return [self expandedSelectionForRange:range] ?: [super attributedTextInRange:range];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/// The menu's Copy is already replaced by the library's own action; this covers the key command.
|
|
102
|
+
- (void)copy:(id)sender
|
|
103
|
+
{
|
|
104
|
+
NSRange selected = self.selectedRange;
|
|
105
|
+
if (self.copySelectionHandler && selected.location != NSNotFound && selected.length > 0) {
|
|
106
|
+
self.copySelectionHandler(selected);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
NSAttributedString *expanded = [self expandedSelectionForRange:self.selectedTextRange];
|
|
110
|
+
if (!expanded) {
|
|
111
|
+
[super copy:sender];
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
copyAttributedStringToPasteboard(expanded, nil, nil);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#pragma mark - Pill menus
|
|
118
|
+
|
|
119
|
+
- (nullable ENRMLinkContextMenus *)linkContextMenus
|
|
120
|
+
{
|
|
121
|
+
id delegate = self.delegate;
|
|
122
|
+
return [delegate conformsToProtocol:@protocol(ENRMLinkContextMenuSource)]
|
|
123
|
+
? [(id<ENRMLinkContextMenuSource>)delegate linkContextMenusForTextView:self]
|
|
124
|
+
: nil;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/// Where the pill at `index` is drawn, in the text view's coordinates.
|
|
128
|
+
- (CGRect)pillFrameAtIndex:(NSUInteger)index
|
|
129
|
+
{
|
|
130
|
+
NSLayoutManager *layoutManager = self.layoutManager;
|
|
131
|
+
NSUInteger glyph = [layoutManager glyphIndexForCharacterAtIndex:index];
|
|
132
|
+
CGSize size = [layoutManager attachmentSizeForGlyphAtIndex:glyph];
|
|
133
|
+
if (size.width <= 0 || size.height <= 0)
|
|
134
|
+
return CGRectNull;
|
|
135
|
+
CGRect line = [layoutManager lineFragmentRectForGlyphAtIndex:glyph effectiveRange:NULL];
|
|
136
|
+
// TextKit places an attachment glyph at the bottom edge of its bounds.
|
|
137
|
+
CGPoint location = [layoutManager locationForGlyphAtIndex:glyph];
|
|
138
|
+
UIEdgeInsets inset = self.textContainerInset;
|
|
139
|
+
return CGRectMake(inset.left + line.origin.x + location.x, inset.top + line.origin.y + location.y - size.height,
|
|
140
|
+
size.width, size.height);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Whether the character at `index` is a pill whose link has a menu.
|
|
144
|
+
- (BOOL)presentsLinkMenuAtIndex:(NSUInteger)index
|
|
145
|
+
{
|
|
146
|
+
ENRMLinkContextMenus *menus = [self linkContextMenus];
|
|
147
|
+
NSTextStorage *storage = self.textStorage;
|
|
148
|
+
if (menus.entries.count == 0 || index >= storage.length)
|
|
149
|
+
return NO;
|
|
150
|
+
id attachment = [storage attribute:NSAttachmentAttributeName atIndex:index effectiveRange:NULL];
|
|
151
|
+
return [attachment isKindOfClass:ENRMLinkPillAttachment.class] &&
|
|
152
|
+
[menus hasMenuForURL:linkURLAtRange(self, NSMakeRange(index, 1))];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/// The character index of the pill under `point` when its link has a menu, else NSNotFound.
|
|
156
|
+
- (NSUInteger)menuPillIndexAtPoint:(CGPoint)point
|
|
157
|
+
{
|
|
158
|
+
if ([self linkContextMenus].entries.count == 0)
|
|
159
|
+
return NSNotFound;
|
|
160
|
+
NSUInteger index = ENRMCharacterIndexAtPoint(self, point);
|
|
161
|
+
if (index == NSNotFound || ![self presentsLinkMenuAtIndex:index] ||
|
|
162
|
+
!CGRectContainsPoint([self pillFrameAtIndex:index], point))
|
|
163
|
+
return NSNotFound;
|
|
164
|
+
return index;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
- (void)setPill:(ENRMLinkPillAttachment *)pill lifted:(BOOL)lifted
|
|
168
|
+
{
|
|
169
|
+
pill.lifted = lifted;
|
|
170
|
+
NSTextStorage *storage = self.textStorage;
|
|
171
|
+
[storage enumerateAttribute:NSAttachmentAttributeName
|
|
172
|
+
inRange:NSMakeRange(0, storage.length)
|
|
173
|
+
options:0
|
|
174
|
+
usingBlock:^(id value, NSRange range, BOOL *stop) {
|
|
175
|
+
if (value != pill)
|
|
176
|
+
return;
|
|
177
|
+
[self.layoutManager invalidateDisplayForCharacterRange:range];
|
|
178
|
+
*stop = YES;
|
|
179
|
+
}];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
- (void)restoreLiftedPill
|
|
183
|
+
{
|
|
184
|
+
if (_liftedPill)
|
|
185
|
+
[self setPill:_liftedPill lifted:NO];
|
|
186
|
+
_liftedPill = nil;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
190
|
+
configurationForMenuAtLocation:(CGPoint)location
|
|
191
|
+
{
|
|
192
|
+
[_pillLift end];
|
|
193
|
+
_pillMenuIndex = [self menuPillIndexAtPoint:location];
|
|
194
|
+
if (_pillMenuIndex == NSNotFound)
|
|
195
|
+
return nil;
|
|
196
|
+
UIMenu *menu = [[self linkContextMenus] menuForURL:linkURLAtRange(self, NSMakeRange(_pillMenuIndex, 1))
|
|
197
|
+
title:linkTitleAtIndex(self.textStorage, _pillMenuIndex)];
|
|
198
|
+
if (!menu)
|
|
199
|
+
return nil;
|
|
200
|
+
return [UIContextMenuConfiguration
|
|
201
|
+
configurationWithIdentifier:nil
|
|
202
|
+
previewProvider:nil
|
|
203
|
+
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) { return menu; }];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// The pill is lifted as an image of itself, see `ENRMLinkMenuLift`.
|
|
207
|
+
- (UITargetedPreview *)pillMenuPreview
|
|
208
|
+
{
|
|
209
|
+
if (![_pillLift isOverView:self]) {
|
|
210
|
+
NSTextStorage *storage = self.textStorage;
|
|
211
|
+
if (self.window == nil || _pillMenuIndex >= storage.length)
|
|
212
|
+
return nil;
|
|
213
|
+
id attachment = [storage attribute:NSAttachmentAttributeName atIndex:_pillMenuIndex effectiveRange:NULL];
|
|
214
|
+
CGRect frame = [self pillFrameAtIndex:_pillMenuIndex];
|
|
215
|
+
if (![attachment isKindOfClass:ENRMLinkPillAttachment.class] || CGRectIsNull(frame))
|
|
216
|
+
return nil;
|
|
217
|
+
UIImage *image = [(ENRMLinkPillAttachment *)attachment imageForBounds:(CGRect){CGPointZero, frame.size}
|
|
218
|
+
textContainer:self.textContainer
|
|
219
|
+
characterIndex:_pillMenuIndex];
|
|
220
|
+
[_pillLift layImage:image atFrame:frame overView:self];
|
|
221
|
+
_liftedPill = attachment;
|
|
222
|
+
[self setPill:_liftedPill lifted:YES];
|
|
223
|
+
}
|
|
224
|
+
return [_pillLift previewWithCornerRadius:_liftedPill.cornerRadius backgroundColor:UIColor.clearColor];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
228
|
+
previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
|
|
229
|
+
{
|
|
230
|
+
return [self pillMenuPreview];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
234
|
+
previewForDismissingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
|
|
235
|
+
{
|
|
236
|
+
return [self pillMenuPreview];
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction
|
|
240
|
+
willEndForConfiguration:(UIContextMenuConfiguration *)configuration
|
|
241
|
+
animator:(id<UIContextMenuInteractionAnimating>)animator
|
|
242
|
+
{
|
|
243
|
+
[_pillLift endWithAnimator:animator];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@end
|
|
247
|
+
#endif
|