react-native-enriched 0.2.1 → 0.4.0
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/README.md +21 -16
- package/android/build.gradle +77 -72
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +21 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +7 -0
- package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.cpp +1 -1
- package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.h +1 -1
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.cpp +276 -0
- package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.h +239 -0
- package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +251 -0
- package/android/gradle.properties +5 -5
- package/android/lint.gradle +70 -0
- package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewPackage.kt → ReactNativeEnrichedPackage.kt} +4 -5
- package/android/src/main/java/com/swmansion/enriched/{utils → common}/AsyncDrawable.kt +50 -15
- package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
- package/android/src/main/java/com/swmansion/enriched/common/EnrichedConstants.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
- package/android/src/main/java/com/swmansion/enriched/{spans/utils → common}/ForceRedrawSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +7 -0
- package/android/src/main/java/com/swmansion/enriched/{utils → common}/ResourceManager.kt +1 -1
- package/android/src/main/java/com/swmansion/enriched/{utils → common/parser}/EnrichedParser.java +228 -160
- package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +79 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBlockQuoteSpan.kt +53 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +91 -0
- package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedCodeBlockSpan.kt +12 -14
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
- package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedImageSpan.kt +68 -51
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedLinkSpan.kt +26 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedMentionSpan.kt +35 -0
- package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedOrderedListSpan.kt +21 -29
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedUnorderedListSpan.kt +13 -17
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedBlockSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedHeadingSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedParagraphSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedZeroWidthSpaceSpan.kt +2 -3
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputConnectionWrapper.kt +140 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +83 -0
- package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputView.kt → textinput/EnrichedTextInputView.kt} +322 -157
- package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewLayoutManager.kt → textinput/EnrichedTextInputViewLayoutManager.kt} +4 -2
- package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewManager.kt → textinput/EnrichedTextInputViewManager.kt} +182 -66
- package/android/src/main/java/com/swmansion/enriched/{MeasurementStore.kt → textinput/MeasurementStore.kt} +75 -25
- package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/MentionHandler.kt +22 -12
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeHtmlEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeSelectionEvent.kt +11 -10
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeStateEvent.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeTextEvent.kt +30 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputBlurEvent.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputFocusEvent.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputKeyPressEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnLinkDetectedEvent.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionDetectedEvent.kt +11 -10
- package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionEvent.kt +10 -9
- package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
- package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnRequestHtmlResultEvent.kt +2 -3
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt +241 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/HtmlStyle.kt +129 -57
- package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/InlineStyles.kt +30 -13
- package/android/src/main/java/com/swmansion/enriched/textinput/styles/ListStyles.kt +263 -0
- package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParagraphStyles.kt +94 -34
- package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParametrizedStyles.kt +143 -67
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedEditableFactory.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSelection.kt +84 -54
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt +304 -0
- package/android/src/main/java/com/swmansion/enriched/{utils/Utils.kt → textinput/utils/EnrichedSpannable.kt} +22 -31
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +16 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
- package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedSpanWatcher.kt +56 -24
- package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedTextWatcher.kt +37 -14
- package/android/src/main/new_arch/CMakeLists.txt +7 -1
- package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
- package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +15 -0
- package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.h +1 -1
- package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.h +2 -2
- package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h +46 -0
- package/ios/EnrichedTextInputView.h +2 -1
- package/ios/EnrichedTextInputView.mm +603 -60
- package/ios/config/InputConfig.h +28 -0
- package/ios/config/InputConfig.mm +237 -8
- package/ios/extensions/ImageExtension.h +35 -0
- package/ios/extensions/ImageExtension.mm +156 -0
- package/ios/{utils → extensions}/LayoutManagerExtension.mm +115 -95
- package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.cpp +1 -1
- package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.h +1 -1
- package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.cpp +276 -0
- package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.h +239 -0
- package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +10 -0
- package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +251 -0
- package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/RCTComponentViewHelpers.h +95 -0
- package/ios/inputParser/InputParser.mm +218 -18
- package/ios/inputTextView/InputTextView.mm +118 -0
- package/ios/{attachments → interfaces}/ImageAttachment.h +1 -0
- package/ios/interfaces/ImageAttachment.mm +46 -0
- package/ios/interfaces/LinkRegexConfig.h +19 -0
- package/ios/interfaces/LinkRegexConfig.mm +37 -0
- package/ios/{utils → interfaces}/MentionStyleProps.mm +2 -2
- package/ios/{utils → interfaces}/StyleHeaders.h +22 -1
- package/ios/{utils → interfaces}/StyleTypeEnum.h +4 -0
- package/ios/internals/EnrichedTextInputViewState.cpp +6 -6
- package/ios/styles/BlockQuoteStyle.mm +5 -5
- package/ios/styles/BoldStyle.mm +21 -6
- package/ios/styles/CheckboxListStyle.mm +321 -0
- package/ios/styles/CodeBlockStyle.mm +5 -5
- package/ios/styles/H1Style.mm +3 -0
- package/ios/styles/H2Style.mm +3 -0
- package/ios/styles/H3Style.mm +3 -0
- package/ios/styles/H4Style.mm +20 -0
- package/ios/styles/H5Style.mm +20 -0
- package/ios/styles/H6Style.mm +20 -0
- package/ios/styles/HeadingStyleBase.mm +161 -72
- package/ios/styles/ImageStyle.mm +5 -5
- package/ios/styles/InlineCodeStyle.mm +30 -19
- package/ios/styles/ItalicStyle.mm +5 -5
- package/ios/styles/LinkStyle.mm +98 -40
- package/ios/styles/MentionStyle.mm +4 -4
- package/ios/styles/OrderedListStyle.mm +5 -5
- package/ios/styles/StrikethroughStyle.mm +5 -5
- package/ios/styles/UnderlineStyle.mm +5 -5
- package/ios/styles/UnorderedListStyle.mm +5 -5
- package/ios/utils/CheckboxHitTestUtils.h +10 -0
- package/ios/utils/CheckboxHitTestUtils.mm +123 -0
- package/ios/utils/ParagraphAttributesUtils.h +4 -0
- package/ios/utils/ParagraphAttributesUtils.mm +142 -45
- package/ios/utils/ParagraphsUtils.mm +4 -4
- package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
- package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
- package/ios/utils/ZeroWidthSpaceUtils.mm +14 -3
- package/lib/module/EnrichedTextInput.js +57 -11
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +175 -18
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +18 -0
- package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
- package/lib/module/utils/nullthrows.js +9 -0
- package/lib/module/utils/nullthrows.js.map +1 -0
- package/lib/module/utils/regexParser.js +46 -0
- package/lib/module/utils/regexParser.js.map +1 -0
- package/lib/typescript/src/EnrichedTextInput.d.ts +20 -51
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/{EnrichedTextInputNativeComponent.d.ts → spec/EnrichedTextInputNativeComponent.d.ts} +154 -18
- package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +58 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
- package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
- package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
- package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
- package/lib/typescript/src/utils/regexParser.d.ts +3 -0
- package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
- package/package.json +13 -9
- package/src/EnrichedTextInput.tsx +88 -63
- package/src/index.tsx +5 -1
- package/src/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +175 -18
- package/src/types.ts +59 -0
- package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +20 -5
- package/src/utils/nullthrows.ts +7 -0
- package/src/utils/regexParser.ts +56 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +0 -128
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +0 -102
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +0 -28
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +0 -24
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +0 -30
- package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +0 -27
- package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +0 -27
- package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +0 -30
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +0 -44
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +0 -16
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +0 -23
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +0 -23
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +0 -23
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +0 -27
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +0 -15
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +0 -30
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +0 -42
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +0 -136
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +0 -14
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +0 -14
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +0 -4
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +0 -4
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +0 -4
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +0 -4
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +0 -8
- package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +0 -172
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +0 -204
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +0 -22
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +0 -26
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +0 -26
- package/ios/attachments/ImageAttachment.mm +0 -34
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +0 -128
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +0 -102
- package/lib/module/normalizeHtmlStyle.js.map +0 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
- /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
- /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
- /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
- /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
- /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputComponentDescriptor.h +0 -0
- /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.cpp +0 -0
- /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.cpp +0 -0
- /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.cpp +0 -0
- /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.h +0 -0
- /package/ios/{utils → extensions}/ColorExtension.h +0 -0
- /package/ios/{utils → extensions}/ColorExtension.mm +0 -0
- /package/ios/{utils → extensions}/FontExtension.h +0 -0
- /package/ios/{utils → extensions}/FontExtension.mm +0 -0
- /package/ios/{utils → extensions}/LayoutManagerExtension.h +0 -0
- /package/ios/{utils → extensions}/StringExtension.h +0 -0
- /package/ios/{utils → extensions}/StringExtension.mm +0 -0
- /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
- /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
- /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
- /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
- /package/ios/{utils → interfaces}/BaseStyleProtocol.h +0 -0
- /package/ios/{utils → interfaces}/ImageData.h +0 -0
- /package/ios/{utils → interfaces}/ImageData.mm +0 -0
- /package/ios/{utils → interfaces}/LinkData.h +0 -0
- /package/ios/{utils → interfaces}/LinkData.mm +0 -0
- /package/ios/{attachments → interfaces}/MediaAttachment.h +0 -0
- /package/ios/{attachments → interfaces}/MediaAttachment.mm +0 -0
- /package/ios/{utils → interfaces}/MentionParams.h +0 -0
- /package/ios/{utils → interfaces}/MentionParams.mm +0 -0
- /package/ios/{utils → interfaces}/MentionStyleProps.h +0 -0
- /package/ios/{utils → interfaces}/StylePair.h +0 -0
- /package/ios/{utils → interfaces}/StylePair.mm +0 -0
- /package/ios/{utils → interfaces}/TextDecorationLineEnum.h +0 -0
- /package/ios/{utils → interfaces}/TextDecorationLineEnum.mm +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
package com.swmansion.enriched.textinput.utils
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Arguments
|
|
4
|
+
import com.facebook.react.bridge.ReactContext
|
|
5
|
+
import com.facebook.react.bridge.WritableMap
|
|
6
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
7
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
8
|
+
import com.swmansion.enriched.textinput.EnrichedTextInputView
|
|
9
|
+
import com.swmansion.enriched.textinput.events.OnChangeStateEvent
|
|
10
|
+
import com.swmansion.enriched.textinput.spans.EnrichedSpans
|
|
11
|
+
|
|
12
|
+
class EnrichedSpanState(
|
|
13
|
+
private val view: EnrichedTextInputView,
|
|
14
|
+
) {
|
|
15
|
+
private var previousPayload: WritableMap? = null
|
|
16
|
+
|
|
17
|
+
var boldStart: Int? = null
|
|
18
|
+
private set
|
|
19
|
+
var italicStart: Int? = null
|
|
20
|
+
private set
|
|
21
|
+
var underlineStart: Int? = null
|
|
22
|
+
private set
|
|
23
|
+
var strikethroughStart: Int? = null
|
|
24
|
+
private set
|
|
25
|
+
var inlineCodeStart: Int? = null
|
|
26
|
+
private set
|
|
27
|
+
var h1Start: Int? = null
|
|
28
|
+
private set
|
|
29
|
+
var h2Start: Int? = null
|
|
30
|
+
private set
|
|
31
|
+
var h3Start: Int? = null
|
|
32
|
+
private set
|
|
33
|
+
var h4Start: Int? = null
|
|
34
|
+
private set
|
|
35
|
+
var h5Start: Int? = null
|
|
36
|
+
private set
|
|
37
|
+
var h6Start: Int? = null
|
|
38
|
+
private set
|
|
39
|
+
var codeBlockStart: Int? = null
|
|
40
|
+
private set
|
|
41
|
+
var blockQuoteStart: Int? = null
|
|
42
|
+
private set
|
|
43
|
+
var orderedListStart: Int? = null
|
|
44
|
+
private set
|
|
45
|
+
var unorderedListStart: Int? = null
|
|
46
|
+
private set
|
|
47
|
+
var checkboxListStart: Int? = null
|
|
48
|
+
private set
|
|
49
|
+
var linkStart: Int? = null
|
|
50
|
+
private set
|
|
51
|
+
var imageStart: Int? = null
|
|
52
|
+
private set
|
|
53
|
+
var mentionStart: Int? = null
|
|
54
|
+
private set
|
|
55
|
+
|
|
56
|
+
fun setBoldStart(start: Int?) {
|
|
57
|
+
this.boldStart = start
|
|
58
|
+
emitStateChangeEvent()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fun setItalicStart(start: Int?) {
|
|
62
|
+
this.italicStart = start
|
|
63
|
+
emitStateChangeEvent()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fun setUnderlineStart(start: Int?) {
|
|
67
|
+
this.underlineStart = start
|
|
68
|
+
emitStateChangeEvent()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fun setStrikethroughStart(start: Int?) {
|
|
72
|
+
this.strikethroughStart = start
|
|
73
|
+
emitStateChangeEvent()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun setInlineCodeStart(start: Int?) {
|
|
77
|
+
this.inlineCodeStart = start
|
|
78
|
+
emitStateChangeEvent()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fun setH1Start(start: Int?) {
|
|
82
|
+
this.h1Start = start
|
|
83
|
+
emitStateChangeEvent()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fun setH2Start(start: Int?) {
|
|
87
|
+
this.h2Start = start
|
|
88
|
+
emitStateChangeEvent()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fun setH3Start(start: Int?) {
|
|
92
|
+
this.h3Start = start
|
|
93
|
+
emitStateChangeEvent()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fun setH4Start(start: Int?) {
|
|
97
|
+
this.h4Start = start
|
|
98
|
+
emitStateChangeEvent()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fun setH5Start(start: Int?) {
|
|
102
|
+
this.h5Start = start
|
|
103
|
+
emitStateChangeEvent()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
fun setH6Start(start: Int?) {
|
|
107
|
+
this.h6Start = start
|
|
108
|
+
emitStateChangeEvent()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fun setCodeBlockStart(start: Int?) {
|
|
112
|
+
this.codeBlockStart = start
|
|
113
|
+
emitStateChangeEvent()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fun setBlockQuoteStart(start: Int?) {
|
|
117
|
+
this.blockQuoteStart = start
|
|
118
|
+
emitStateChangeEvent()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fun setOrderedListStart(start: Int?) {
|
|
122
|
+
this.orderedListStart = start
|
|
123
|
+
emitStateChangeEvent()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fun setUnorderedListStart(start: Int?) {
|
|
127
|
+
this.unorderedListStart = start
|
|
128
|
+
emitStateChangeEvent()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fun setCheckboxListStart(start: Int?) {
|
|
132
|
+
this.checkboxListStart = start
|
|
133
|
+
emitStateChangeEvent()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
fun setLinkStart(start: Int?) {
|
|
137
|
+
this.linkStart = start
|
|
138
|
+
emitStateChangeEvent()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fun setImageStart(start: Int?) {
|
|
142
|
+
this.imageStart = start
|
|
143
|
+
emitStateChangeEvent()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
fun setMentionStart(start: Int?) {
|
|
147
|
+
this.mentionStart = start
|
|
148
|
+
emitStateChangeEvent()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
fun getStart(name: String): Int? {
|
|
152
|
+
val start =
|
|
153
|
+
when (name) {
|
|
154
|
+
EnrichedSpans.BOLD -> boldStart
|
|
155
|
+
EnrichedSpans.ITALIC -> italicStart
|
|
156
|
+
EnrichedSpans.UNDERLINE -> underlineStart
|
|
157
|
+
EnrichedSpans.STRIKETHROUGH -> strikethroughStart
|
|
158
|
+
EnrichedSpans.INLINE_CODE -> inlineCodeStart
|
|
159
|
+
EnrichedSpans.H1 -> h1Start
|
|
160
|
+
EnrichedSpans.H2 -> h2Start
|
|
161
|
+
EnrichedSpans.H3 -> h3Start
|
|
162
|
+
EnrichedSpans.H4 -> h4Start
|
|
163
|
+
EnrichedSpans.H5 -> h5Start
|
|
164
|
+
EnrichedSpans.H6 -> h6Start
|
|
165
|
+
EnrichedSpans.CODE_BLOCK -> codeBlockStart
|
|
166
|
+
EnrichedSpans.BLOCK_QUOTE -> blockQuoteStart
|
|
167
|
+
EnrichedSpans.ORDERED_LIST -> orderedListStart
|
|
168
|
+
EnrichedSpans.UNORDERED_LIST -> unorderedListStart
|
|
169
|
+
EnrichedSpans.CHECKBOX_LIST -> checkboxListStart
|
|
170
|
+
EnrichedSpans.LINK -> linkStart
|
|
171
|
+
EnrichedSpans.IMAGE -> imageStart
|
|
172
|
+
EnrichedSpans.MENTION -> mentionStart
|
|
173
|
+
else -> null
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return start
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
fun setStart(
|
|
180
|
+
name: String,
|
|
181
|
+
start: Int?,
|
|
182
|
+
) {
|
|
183
|
+
when (name) {
|
|
184
|
+
EnrichedSpans.BOLD -> setBoldStart(start)
|
|
185
|
+
EnrichedSpans.ITALIC -> setItalicStart(start)
|
|
186
|
+
EnrichedSpans.UNDERLINE -> setUnderlineStart(start)
|
|
187
|
+
EnrichedSpans.STRIKETHROUGH -> setStrikethroughStart(start)
|
|
188
|
+
EnrichedSpans.INLINE_CODE -> setInlineCodeStart(start)
|
|
189
|
+
EnrichedSpans.H1 -> setH1Start(start)
|
|
190
|
+
EnrichedSpans.H2 -> setH2Start(start)
|
|
191
|
+
EnrichedSpans.H3 -> setH3Start(start)
|
|
192
|
+
EnrichedSpans.H4 -> setH4Start(start)
|
|
193
|
+
EnrichedSpans.H5 -> setH5Start(start)
|
|
194
|
+
EnrichedSpans.H6 -> setH6Start(start)
|
|
195
|
+
EnrichedSpans.CODE_BLOCK -> setCodeBlockStart(start)
|
|
196
|
+
EnrichedSpans.BLOCK_QUOTE -> setBlockQuoteStart(start)
|
|
197
|
+
EnrichedSpans.ORDERED_LIST -> setOrderedListStart(start)
|
|
198
|
+
EnrichedSpans.UNORDERED_LIST -> setUnorderedListStart(start)
|
|
199
|
+
EnrichedSpans.CHECKBOX_LIST -> setCheckboxListStart(start)
|
|
200
|
+
EnrichedSpans.LINK -> setLinkStart(start)
|
|
201
|
+
EnrichedSpans.IMAGE -> setImageStart(start)
|
|
202
|
+
EnrichedSpans.MENTION -> setMentionStart(start)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private fun emitStateChangeEvent() {
|
|
207
|
+
val context = view.context as ReactContext
|
|
208
|
+
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
209
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
210
|
+
|
|
211
|
+
dispatchPayload(dispatcher, surfaceId)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private fun dispatchPayload(
|
|
215
|
+
dispatcher: EventDispatcher?,
|
|
216
|
+
surfaceId: Int,
|
|
217
|
+
) {
|
|
218
|
+
val activeStyles =
|
|
219
|
+
listOfNotNull(
|
|
220
|
+
if (boldStart != null) EnrichedSpans.BOLD else null,
|
|
221
|
+
if (italicStart != null) EnrichedSpans.ITALIC else null,
|
|
222
|
+
if (underlineStart != null) EnrichedSpans.UNDERLINE else null,
|
|
223
|
+
if (strikethroughStart != null) EnrichedSpans.STRIKETHROUGH else null,
|
|
224
|
+
if (inlineCodeStart != null) EnrichedSpans.INLINE_CODE else null,
|
|
225
|
+
if (h1Start != null) EnrichedSpans.H1 else null,
|
|
226
|
+
if (h2Start != null) EnrichedSpans.H2 else null,
|
|
227
|
+
if (h3Start != null) EnrichedSpans.H3 else null,
|
|
228
|
+
if (h4Start != null) EnrichedSpans.H4 else null,
|
|
229
|
+
if (h5Start != null) EnrichedSpans.H5 else null,
|
|
230
|
+
if (h6Start != null) EnrichedSpans.H6 else null,
|
|
231
|
+
if (codeBlockStart != null) EnrichedSpans.CODE_BLOCK else null,
|
|
232
|
+
if (blockQuoteStart != null) EnrichedSpans.BLOCK_QUOTE else null,
|
|
233
|
+
if (orderedListStart != null) EnrichedSpans.ORDERED_LIST else null,
|
|
234
|
+
if (unorderedListStart != null) EnrichedSpans.UNORDERED_LIST else null,
|
|
235
|
+
if (checkboxListStart != null) EnrichedSpans.CHECKBOX_LIST else null,
|
|
236
|
+
if (linkStart != null) EnrichedSpans.LINK else null,
|
|
237
|
+
if (imageStart != null) EnrichedSpans.IMAGE else null,
|
|
238
|
+
if (mentionStart != null) EnrichedSpans.MENTION else null,
|
|
239
|
+
)
|
|
240
|
+
val payload = Arguments.createMap()
|
|
241
|
+
payload.putMap("bold", getStyleState(activeStyles, EnrichedSpans.BOLD))
|
|
242
|
+
payload.putMap("italic", getStyleState(activeStyles, EnrichedSpans.ITALIC))
|
|
243
|
+
payload.putMap("underline", getStyleState(activeStyles, EnrichedSpans.UNDERLINE))
|
|
244
|
+
payload.putMap("strikeThrough", getStyleState(activeStyles, EnrichedSpans.STRIKETHROUGH))
|
|
245
|
+
payload.putMap("inlineCode", getStyleState(activeStyles, EnrichedSpans.INLINE_CODE))
|
|
246
|
+
payload.putMap("h1", getStyleState(activeStyles, EnrichedSpans.H1))
|
|
247
|
+
payload.putMap("h2", getStyleState(activeStyles, EnrichedSpans.H2))
|
|
248
|
+
payload.putMap("h3", getStyleState(activeStyles, EnrichedSpans.H3))
|
|
249
|
+
payload.putMap("h4", getStyleState(activeStyles, EnrichedSpans.H4))
|
|
250
|
+
payload.putMap("h5", getStyleState(activeStyles, EnrichedSpans.H5))
|
|
251
|
+
payload.putMap("h6", getStyleState(activeStyles, EnrichedSpans.H6))
|
|
252
|
+
payload.putMap("codeBlock", getStyleState(activeStyles, EnrichedSpans.CODE_BLOCK))
|
|
253
|
+
payload.putMap("blockQuote", getStyleState(activeStyles, EnrichedSpans.BLOCK_QUOTE))
|
|
254
|
+
payload.putMap("orderedList", getStyleState(activeStyles, EnrichedSpans.ORDERED_LIST))
|
|
255
|
+
payload.putMap("unorderedList", getStyleState(activeStyles, EnrichedSpans.UNORDERED_LIST))
|
|
256
|
+
payload.putMap("link", getStyleState(activeStyles, EnrichedSpans.LINK))
|
|
257
|
+
payload.putMap("image", getStyleState(activeStyles, EnrichedSpans.IMAGE))
|
|
258
|
+
payload.putMap("mention", getStyleState(activeStyles, EnrichedSpans.MENTION))
|
|
259
|
+
payload.putMap("checkboxList", getStyleState(activeStyles, EnrichedSpans.CHECKBOX_LIST))
|
|
260
|
+
|
|
261
|
+
// Do not emit event if payload is the same
|
|
262
|
+
if (previousPayload == payload) {
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
previousPayload =
|
|
267
|
+
Arguments.createMap().apply {
|
|
268
|
+
merge(payload)
|
|
269
|
+
}
|
|
270
|
+
dispatcher?.dispatchEvent(
|
|
271
|
+
OnChangeStateEvent(
|
|
272
|
+
surfaceId,
|
|
273
|
+
view.id,
|
|
274
|
+
payload,
|
|
275
|
+
view.experimentalSynchronousEvents,
|
|
276
|
+
),
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private fun getStyleState(
|
|
281
|
+
activeStyles: List<String>,
|
|
282
|
+
type: String,
|
|
283
|
+
): WritableMap {
|
|
284
|
+
val mergingConfig = EnrichedSpans.getMergingConfigForStyle(type, view.htmlStyle)
|
|
285
|
+
val blockingList = mergingConfig?.blockingStyles
|
|
286
|
+
val conflictingList = mergingConfig?.conflictingStyles
|
|
287
|
+
|
|
288
|
+
val state = Arguments.createMap()
|
|
289
|
+
|
|
290
|
+
state.putBoolean("isActive", activeStyles.contains(type))
|
|
291
|
+
|
|
292
|
+
val isBlocking = blockingList?.any { activeStyles.contains(it) } ?: false
|
|
293
|
+
state.putBoolean("isBlocking", isBlocking)
|
|
294
|
+
|
|
295
|
+
val isConflicting = conflictingList?.any { activeStyles.contains(it) } ?: false
|
|
296
|
+
state.putBoolean("isConflicting", isConflicting)
|
|
297
|
+
|
|
298
|
+
return state
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
companion object {
|
|
302
|
+
const val NAME = "ReactNativeEnrichedView"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -1,38 +1,25 @@
|
|
|
1
|
-
package com.swmansion.enriched.utils
|
|
1
|
+
package com.swmansion.enriched.textinput.utils
|
|
2
2
|
|
|
3
3
|
import android.text.Spannable
|
|
4
4
|
import android.text.SpannableString
|
|
5
5
|
import android.text.SpannableStringBuilder
|
|
6
|
-
import
|
|
7
|
-
import com.swmansion.enriched.spans.interfaces.
|
|
8
|
-
import com.swmansion.enriched.spans.interfaces.EnrichedParagraphSpan
|
|
9
|
-
import org.json.JSONObject
|
|
10
|
-
|
|
11
|
-
fun jsonStringToStringMap(json: String): Map<String, String> {
|
|
12
|
-
val result = mutableMapOf<String, String>()
|
|
13
|
-
try {
|
|
14
|
-
val jsonObject = JSONObject(json)
|
|
15
|
-
for (key in jsonObject.keys()) {
|
|
16
|
-
val value = jsonObject.opt(key)
|
|
17
|
-
if (value is String) {
|
|
18
|
-
result[key] = value
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
} catch (e: Exception) {
|
|
22
|
-
Log.w("ReactNativeEnrichedView", "Failed to parse JSON string to Map: $json", e)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return result
|
|
26
|
-
}
|
|
6
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedBlockSpan
|
|
7
|
+
import com.swmansion.enriched.common.spans.interfaces.EnrichedParagraphSpan
|
|
27
8
|
|
|
28
|
-
fun Spannable.getSafeSpanBoundaries(
|
|
9
|
+
fun Spannable.getSafeSpanBoundaries(
|
|
10
|
+
start: Int,
|
|
11
|
+
end: Int,
|
|
12
|
+
): Pair<Int, Int> {
|
|
29
13
|
val safeStart = start.coerceAtMost(end).coerceAtLeast(0)
|
|
30
14
|
val safeEnd = end.coerceAtLeast(start).coerceAtMost(this.length)
|
|
31
15
|
|
|
32
16
|
return Pair(safeStart, safeEnd)
|
|
33
17
|
}
|
|
34
18
|
|
|
35
|
-
fun Spannable.getParagraphBounds(
|
|
19
|
+
fun Spannable.getParagraphBounds(
|
|
20
|
+
start: Int,
|
|
21
|
+
end: Int,
|
|
22
|
+
): Pair<Int, Int> {
|
|
36
23
|
var startPosition = start.coerceAtLeast(0).coerceAtMost(this.length)
|
|
37
24
|
var endPosition = end.coerceAtLeast(0).coerceAtMost(this.length)
|
|
38
25
|
|
|
@@ -54,15 +41,19 @@ fun Spannable.getParagraphBounds(start: Int, end: Int): Pair<Int, Int> {
|
|
|
54
41
|
return Pair(startPosition, endPosition)
|
|
55
42
|
}
|
|
56
43
|
|
|
57
|
-
fun Spannable.getParagraphBounds(index: Int): Pair<Int, Int>
|
|
58
|
-
return this.getParagraphBounds(index, index)
|
|
59
|
-
}
|
|
44
|
+
fun Spannable.getParagraphBounds(index: Int): Pair<Int, Int> = this.getParagraphBounds(index, index)
|
|
60
45
|
|
|
61
|
-
fun Spannable.mergeSpannables(
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
fun Spannable.mergeSpannables(
|
|
47
|
+
start: Int,
|
|
48
|
+
end: Int,
|
|
49
|
+
string: String,
|
|
50
|
+
): Spannable = this.mergeSpannables(start, end, SpannableString(string))
|
|
64
51
|
|
|
65
|
-
fun Spannable.mergeSpannables(
|
|
52
|
+
fun Spannable.mergeSpannables(
|
|
53
|
+
start: Int,
|
|
54
|
+
end: Int,
|
|
55
|
+
spannable: Spannable,
|
|
56
|
+
): Spannable {
|
|
66
57
|
var finalStart = start
|
|
67
58
|
var finalEnd = end
|
|
68
59
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.swmansion.enriched.textinput.utils
|
|
2
|
+
|
|
3
|
+
import android.text.SpannableStringBuilder
|
|
4
|
+
import com.swmansion.enriched.common.EnrichedConstants
|
|
5
|
+
|
|
6
|
+
// Removes zero-width spaces from the given range in the SpannableStringBuilder without affecting spans
|
|
7
|
+
fun SpannableStringBuilder.removeZWS(
|
|
8
|
+
start: Int,
|
|
9
|
+
end: Int,
|
|
10
|
+
) {
|
|
11
|
+
for (i in (end - 1) downTo start) {
|
|
12
|
+
if (this[i] == EnrichedConstants.ZWS) {
|
|
13
|
+
delete(i, i + 1)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
package com.swmansion.enriched.textinput.utils
|
|
2
|
+
|
|
3
|
+
import android.content.ClipData
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.BitmapFactory
|
|
6
|
+
import android.net.Uri
|
|
7
|
+
import android.os.Handler
|
|
8
|
+
import android.os.Looper
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.webkit.MimeTypeMap
|
|
12
|
+
import androidx.core.view.ContentInfoCompat
|
|
13
|
+
import androidx.core.view.OnReceiveContentListener
|
|
14
|
+
import com.facebook.react.bridge.ReactContext
|
|
15
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
16
|
+
import com.swmansion.enriched.textinput.EnrichedTextInputView
|
|
17
|
+
import com.swmansion.enriched.textinput.events.OnPasteImagesEvent
|
|
18
|
+
import java.io.File
|
|
19
|
+
import java.io.FileOutputStream
|
|
20
|
+
import kotlin.io.copyTo
|
|
21
|
+
|
|
22
|
+
class RichContentReceiver(
|
|
23
|
+
private val view: EnrichedTextInputView,
|
|
24
|
+
private val context: ReactContext,
|
|
25
|
+
) : OnReceiveContentListener {
|
|
26
|
+
override fun onReceiveContent(
|
|
27
|
+
view: View,
|
|
28
|
+
contentInfo: ContentInfoCompat,
|
|
29
|
+
): ContentInfoCompat? {
|
|
30
|
+
val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
|
|
31
|
+
val uriContent = split.first
|
|
32
|
+
val remaining = split.second
|
|
33
|
+
|
|
34
|
+
if (uriContent != null) {
|
|
35
|
+
processClipDataInBackground(uriContent.clip)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (remaining != null && remaining.clip.itemCount > 0) {
|
|
39
|
+
val item = remaining.clip.getItemAt(0)
|
|
40
|
+
|
|
41
|
+
this.view.handleTextPaste(item)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun processClipDataInBackground(clip: ClipData) {
|
|
48
|
+
Thread {
|
|
49
|
+
val results = mutableListOf<OnPasteImagesEvent.Companion.PastedImage>()
|
|
50
|
+
|
|
51
|
+
for (i in 0 until clip.itemCount) {
|
|
52
|
+
val item = clip.getItemAt(i)
|
|
53
|
+
val uri = item.uri ?: continue
|
|
54
|
+
val mimeType = getMimeTypeFromUri(uri) ?: continue
|
|
55
|
+
|
|
56
|
+
if (mimeType.startsWith("image/")) {
|
|
57
|
+
val result = saveUriToTempFile(context, uri, mimeType)
|
|
58
|
+
if (result != null) {
|
|
59
|
+
results.add(result)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (results.isNotEmpty()) {
|
|
65
|
+
Handler(Looper.getMainLooper()).post {
|
|
66
|
+
emitOnPasteImageEvent(results)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}.start()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private fun emitOnPasteImageEvent(images: List<OnPasteImagesEvent.Companion.PastedImage>) {
|
|
73
|
+
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
74
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
75
|
+
dispatcher?.dispatchEvent(OnPasteImagesEvent(surfaceId, view.id, images, false))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private fun saveUriToTempFile(
|
|
79
|
+
context: Context,
|
|
80
|
+
uri: Uri,
|
|
81
|
+
mimeType: String,
|
|
82
|
+
): OnPasteImagesEvent.Companion.PastedImage? {
|
|
83
|
+
return try {
|
|
84
|
+
val resolver = context.contentResolver
|
|
85
|
+
val ext = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
|
|
86
|
+
val file = File.createTempFile("temp", ".$ext", context.cacheDir)
|
|
87
|
+
|
|
88
|
+
// Copy Stream
|
|
89
|
+
resolver.openInputStream(uri).use { input ->
|
|
90
|
+
if (input == null) return null
|
|
91
|
+
FileOutputStream(file).use { output ->
|
|
92
|
+
input.copyTo(output)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Decode Dimensions
|
|
97
|
+
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
|
98
|
+
BitmapFactory.decodeFile(file.absolutePath, options)
|
|
99
|
+
|
|
100
|
+
OnPasteImagesEvent.Companion.PastedImage(
|
|
101
|
+
uri = "file://${file.absolutePath}",
|
|
102
|
+
type = mimeType,
|
|
103
|
+
width = options.outWidth.toDouble(),
|
|
104
|
+
height = options.outHeight.toDouble(),
|
|
105
|
+
)
|
|
106
|
+
} catch (e: Exception) {
|
|
107
|
+
Log.e("RichContentReceiver", "Failed to save URI: $uri", e)
|
|
108
|
+
null
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private fun getMimeTypeFromUri(uri: Uri): String? {
|
|
113
|
+
var mimeType = context.contentResolver.getType(uri)
|
|
114
|
+
|
|
115
|
+
if (mimeType == null) {
|
|
116
|
+
val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
|
|
117
|
+
|
|
118
|
+
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return mimeType
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
companion object {
|
|
125
|
+
val MIME_TYPES = arrayOf("image/*", "text/*")
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
package com.swmansion.enriched.textinput.utils
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.text.Selection
|
|
5
|
+
import android.text.Spannable
|
|
6
|
+
import android.text.Spanned
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import android.view.MotionEvent
|
|
9
|
+
import android.widget.TextView
|
|
10
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputCheckboxListSpan
|
|
11
|
+
import org.json.JSONObject
|
|
12
|
+
|
|
13
|
+
fun jsonStringToStringMap(json: String): Map<String, String> {
|
|
14
|
+
val result = mutableMapOf<String, String>()
|
|
15
|
+
try {
|
|
16
|
+
val jsonObject = JSONObject(json)
|
|
17
|
+
for (key in jsonObject.keys()) {
|
|
18
|
+
val value = jsonObject.opt(key)
|
|
19
|
+
if (value is String) {
|
|
20
|
+
result[key] = value
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} catch (e: Exception) {
|
|
24
|
+
Log.w("ReactNativeEnrichedView", "Failed to parse JSON string to Map: $json", e)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return result
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Sets a touch listener on TextView which is responsible for detecting touches on checkbox icons
|
|
31
|
+
// We don't use ClickableSpan because it works fine only when LinkMovementMethod is set on TextView
|
|
32
|
+
// Which breaks text selection and other features
|
|
33
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
34
|
+
fun TextView.setCheckboxClickListener() {
|
|
35
|
+
var isDownOnCheckbox = false
|
|
36
|
+
|
|
37
|
+
setOnTouchListener { v, event ->
|
|
38
|
+
val tv = v as TextView
|
|
39
|
+
val layout = tv.layout ?: return@setOnTouchListener false
|
|
40
|
+
val spannable = tv.text as? Spanned ?: return@setOnTouchListener false
|
|
41
|
+
|
|
42
|
+
// Get touch coordinates relative to the text content
|
|
43
|
+
val x = event.x.toInt() - tv.totalPaddingLeft + tv.scrollX
|
|
44
|
+
val y = event.y.toInt() - tv.totalPaddingTop + tv.scrollY
|
|
45
|
+
|
|
46
|
+
// Identify the line and whether it's the first line of the span
|
|
47
|
+
val line = layout.getLineForVertical(y)
|
|
48
|
+
val lineStart = layout.getLineStart(line)
|
|
49
|
+
|
|
50
|
+
// Find spans for specific line
|
|
51
|
+
val spans = spannable.getSpans(lineStart, lineStart, EnrichedInputCheckboxListSpan::class.java)
|
|
52
|
+
if (spans.isEmpty()) return@setOnTouchListener false
|
|
53
|
+
|
|
54
|
+
// There should be only one span per line as we don't support nested lists
|
|
55
|
+
val span = spans[0]
|
|
56
|
+
val isFirstLine = spannable.getSpanStart(span) == lineStart
|
|
57
|
+
val marginWidth = span.getLeadingMargin(true)
|
|
58
|
+
|
|
59
|
+
// Check if touch is on checkbox icon area (which is in the leading margin on the first line)
|
|
60
|
+
val isInHotZone = isFirstLine && x in 0..marginWidth
|
|
61
|
+
|
|
62
|
+
when (event.action) {
|
|
63
|
+
MotionEvent.ACTION_DOWN -> {
|
|
64
|
+
if (isInHotZone) {
|
|
65
|
+
isDownOnCheckbox = true
|
|
66
|
+
return@setOnTouchListener true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
MotionEvent.ACTION_UP -> {
|
|
71
|
+
if (isDownOnCheckbox && isInHotZone) {
|
|
72
|
+
val spannable = tv.text as? Spannable
|
|
73
|
+
if (spannable != null) {
|
|
74
|
+
val start = spannable.getSpanStart(span)
|
|
75
|
+
val end = spannable.getSpanEnd(span)
|
|
76
|
+
val flags = spannable.getSpanFlags(span)
|
|
77
|
+
span.isChecked = !span.isChecked
|
|
78
|
+
|
|
79
|
+
// Reapply span so changes are visible without need to redraw entire TextView
|
|
80
|
+
spannable.removeSpan(span)
|
|
81
|
+
spannable.setSpan(span, start, end, flags)
|
|
82
|
+
|
|
83
|
+
// For focused input, ensure cursor is active for affected paragraph
|
|
84
|
+
if (tv.isFocused) {
|
|
85
|
+
val currentCursor = Selection.getSelectionEnd(spannable)
|
|
86
|
+
if (currentCursor < start || currentCursor > end) {
|
|
87
|
+
Selection.setSelection(spannable, end)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
isDownOnCheckbox = false
|
|
93
|
+
return@setOnTouchListener true
|
|
94
|
+
}
|
|
95
|
+
isDownOnCheckbox = false
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
MotionEvent.ACTION_CANCEL -> {
|
|
99
|
+
isDownOnCheckbox = false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Let TextView handle other touches (e.g., for selection)
|
|
104
|
+
false
|
|
105
|
+
}
|
|
106
|
+
}
|