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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.swmansion.enriched
|
|
1
|
+
package com.swmansion.enriched.textinput
|
|
2
2
|
|
|
3
3
|
import android.content.ClipData
|
|
4
4
|
import android.content.ClipboardManager
|
|
@@ -13,12 +13,19 @@ import android.text.InputType
|
|
|
13
13
|
import android.text.Spannable
|
|
14
14
|
import android.util.AttributeSet
|
|
15
15
|
import android.util.Log
|
|
16
|
+
import android.util.Patterns
|
|
16
17
|
import android.util.TypedValue
|
|
17
18
|
import android.view.Gravity
|
|
18
19
|
import android.view.MotionEvent
|
|
20
|
+
import android.view.inputmethod.EditorInfo
|
|
21
|
+
import android.view.inputmethod.InputConnection
|
|
19
22
|
import android.view.inputmethod.InputMethodManager
|
|
20
23
|
import androidx.appcompat.widget.AppCompatEditText
|
|
24
|
+
import androidx.core.view.ViewCompat
|
|
25
|
+
import androidx.core.view.inputmethod.EditorInfoCompat
|
|
26
|
+
import androidx.core.view.inputmethod.InputConnectionCompat
|
|
21
27
|
import com.facebook.react.bridge.ReactContext
|
|
28
|
+
import com.facebook.react.bridge.ReadableMap
|
|
22
29
|
import com.facebook.react.common.ReactConstants
|
|
23
30
|
import com.facebook.react.uimanager.PixelUtil
|
|
24
31
|
import com.facebook.react.uimanager.StateWrapper
|
|
@@ -26,30 +33,38 @@ import com.facebook.react.uimanager.UIManagerHelper
|
|
|
26
33
|
import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
|
|
27
34
|
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
|
|
28
35
|
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
|
29
|
-
import com.swmansion.enriched.
|
|
30
|
-
import com.swmansion.enriched.
|
|
31
|
-
import com.swmansion.enriched.events.
|
|
32
|
-
import com.swmansion.enriched.events.
|
|
33
|
-
import com.swmansion.enriched.
|
|
34
|
-
import com.swmansion.enriched.
|
|
35
|
-
import com.swmansion.enriched.spans.
|
|
36
|
-
import com.swmansion.enriched.spans.
|
|
37
|
-
import com.swmansion.enriched.spans.
|
|
38
|
-
import com.swmansion.enriched.spans.
|
|
39
|
-
import com.swmansion.enriched.
|
|
40
|
-
import com.swmansion.enriched.
|
|
41
|
-
import com.swmansion.enriched.
|
|
42
|
-
import com.swmansion.enriched.
|
|
43
|
-
import com.swmansion.enriched.
|
|
44
|
-
import com.swmansion.enriched.
|
|
45
|
-
import com.swmansion.enriched.
|
|
46
|
-
import com.swmansion.enriched.
|
|
47
|
-
import com.swmansion.enriched.
|
|
48
|
-
import com.swmansion.enriched.
|
|
49
|
-
import com.swmansion.enriched.
|
|
36
|
+
import com.swmansion.enriched.common.EnrichedConstants
|
|
37
|
+
import com.swmansion.enriched.common.parser.EnrichedParser
|
|
38
|
+
import com.swmansion.enriched.textinput.events.MentionHandler
|
|
39
|
+
import com.swmansion.enriched.textinput.events.OnInputBlurEvent
|
|
40
|
+
import com.swmansion.enriched.textinput.events.OnInputFocusEvent
|
|
41
|
+
import com.swmansion.enriched.textinput.events.OnRequestHtmlResultEvent
|
|
42
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH1Span
|
|
43
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH2Span
|
|
44
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH3Span
|
|
45
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH4Span
|
|
46
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH5Span
|
|
47
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputH6Span
|
|
48
|
+
import com.swmansion.enriched.textinput.spans.EnrichedInputImageSpan
|
|
49
|
+
import com.swmansion.enriched.textinput.spans.EnrichedSpans
|
|
50
|
+
import com.swmansion.enriched.textinput.spans.interfaces.EnrichedInputSpan
|
|
51
|
+
import com.swmansion.enriched.textinput.styles.HtmlStyle
|
|
52
|
+
import com.swmansion.enriched.textinput.styles.InlineStyles
|
|
53
|
+
import com.swmansion.enriched.textinput.styles.ListStyles
|
|
54
|
+
import com.swmansion.enriched.textinput.styles.ParagraphStyles
|
|
55
|
+
import com.swmansion.enriched.textinput.styles.ParametrizedStyles
|
|
56
|
+
import com.swmansion.enriched.textinput.utils.EnrichedEditableFactory
|
|
57
|
+
import com.swmansion.enriched.textinput.utils.EnrichedSelection
|
|
58
|
+
import com.swmansion.enriched.textinput.utils.EnrichedSpanState
|
|
59
|
+
import com.swmansion.enriched.textinput.utils.RichContentReceiver
|
|
60
|
+
import com.swmansion.enriched.textinput.utils.mergeSpannables
|
|
61
|
+
import com.swmansion.enriched.textinput.utils.setCheckboxClickListener
|
|
62
|
+
import com.swmansion.enriched.textinput.watchers.EnrichedSpanWatcher
|
|
63
|
+
import com.swmansion.enriched.textinput.watchers.EnrichedTextWatcher
|
|
64
|
+
import java.util.regex.Pattern
|
|
65
|
+
import java.util.regex.PatternSyntaxException
|
|
50
66
|
import kotlin.math.ceil
|
|
51
67
|
|
|
52
|
-
|
|
53
68
|
class EnrichedTextInputView : AppCompatEditText {
|
|
54
69
|
var stateWrapper: StateWrapper? = null
|
|
55
70
|
val selection: EnrichedSelection? = EnrichedSelection(this)
|
|
@@ -65,16 +80,19 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
65
80
|
val mentionHandler: MentionHandler? = MentionHandler(this)
|
|
66
81
|
var htmlStyle: HtmlStyle = HtmlStyle(this, null)
|
|
67
82
|
set(value) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
if (field != value) {
|
|
84
|
+
val prev = field
|
|
85
|
+
field = value
|
|
86
|
+
reApplyHtmlStyleForSpans(prev, value)
|
|
87
|
+
}
|
|
73
88
|
}
|
|
89
|
+
|
|
90
|
+
var linkRegex: Pattern? = Patterns.WEB_URL
|
|
74
91
|
var spanWatcher: EnrichedSpanWatcher? = null
|
|
75
92
|
var layoutManager: EnrichedTextInputViewLayoutManager = EnrichedTextInputViewLayoutManager(this)
|
|
76
93
|
|
|
77
|
-
var shouldEmitHtml: Boolean =
|
|
94
|
+
var shouldEmitHtml: Boolean = false
|
|
95
|
+
var shouldEmitOnChangeText: Boolean = false
|
|
78
96
|
var experimentalSynchronousEvents: Boolean = false
|
|
79
97
|
|
|
80
98
|
var fontSize: Float? = null
|
|
@@ -89,6 +107,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
89
107
|
private var defaultValueDirty: Boolean = false
|
|
90
108
|
|
|
91
109
|
private var inputMethodManager: InputMethodManager? = null
|
|
110
|
+
private val spannableFactory = EnrichedTextInputSpannableFactory()
|
|
92
111
|
|
|
93
112
|
constructor(context: Context) : super(context) {
|
|
94
113
|
prepareComponent()
|
|
@@ -101,13 +120,33 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
101
120
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
|
102
121
|
context,
|
|
103
122
|
attrs,
|
|
104
|
-
defStyleAttr
|
|
123
|
+
defStyleAttr,
|
|
105
124
|
) {
|
|
106
125
|
prepareComponent()
|
|
107
126
|
}
|
|
108
127
|
|
|
128
|
+
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
|
|
129
|
+
var inputConnection = super.onCreateInputConnection(outAttrs)
|
|
130
|
+
if (inputConnection != null) {
|
|
131
|
+
inputConnection =
|
|
132
|
+
EnrichedTextInputConnectionWrapper(
|
|
133
|
+
inputConnection,
|
|
134
|
+
context as ReactContext,
|
|
135
|
+
this,
|
|
136
|
+
experimentalSynchronousEvents,
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return inputConnection
|
|
141
|
+
}
|
|
142
|
+
|
|
109
143
|
init {
|
|
110
144
|
inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
145
|
+
ViewCompat.setOnReceiveContentListener(
|
|
146
|
+
this,
|
|
147
|
+
RichContentReceiver.MIME_TYPES,
|
|
148
|
+
RichContentReceiver(this, context as ReactContext),
|
|
149
|
+
)
|
|
111
150
|
}
|
|
112
151
|
|
|
113
152
|
private fun prepareComponent() {
|
|
@@ -124,8 +163,15 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
124
163
|
setPadding(0, 0, 0, 0)
|
|
125
164
|
setBackgroundColor(Color.TRANSPARENT)
|
|
126
165
|
|
|
127
|
-
|
|
166
|
+
// Ensure that every time new editable is created, it has EnrichedSpanWatcher attached
|
|
167
|
+
val spanWatcher = EnrichedSpanWatcher(this)
|
|
168
|
+
this.spanWatcher = spanWatcher
|
|
169
|
+
|
|
170
|
+
setEditableFactory(EnrichedEditableFactory(spanWatcher))
|
|
128
171
|
addTextChangedListener(EnrichedTextWatcher(this))
|
|
172
|
+
|
|
173
|
+
// Handle checkbox list item clicks
|
|
174
|
+
this.setCheckboxClickListener()
|
|
129
175
|
}
|
|
130
176
|
|
|
131
177
|
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L295C1-L296C1
|
|
@@ -138,31 +184,32 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
138
184
|
this.parent.requestDisallowInterceptTouchEvent(true)
|
|
139
185
|
}
|
|
140
186
|
|
|
141
|
-
MotionEvent.ACTION_MOVE ->
|
|
187
|
+
MotionEvent.ACTION_MOVE -> {
|
|
142
188
|
if (detectScrollMovement) {
|
|
143
189
|
if (!canScrollVertically(-1) &&
|
|
144
190
|
!canScrollVertically(1) &&
|
|
145
191
|
!canScrollHorizontally(-1) &&
|
|
146
|
-
!canScrollHorizontally(1)
|
|
192
|
+
!canScrollHorizontally(1)
|
|
193
|
+
) {
|
|
147
194
|
// We cannot scroll, let parent views take care of these touches.
|
|
148
195
|
this.parent.requestDisallowInterceptTouchEvent(false)
|
|
149
196
|
}
|
|
150
197
|
detectScrollMovement = false
|
|
151
198
|
}
|
|
199
|
+
}
|
|
152
200
|
}
|
|
153
201
|
|
|
154
202
|
return super.onTouchEvent(ev)
|
|
155
203
|
}
|
|
156
204
|
|
|
157
|
-
override fun canScrollVertically(direction: Int): Boolean
|
|
158
|
-
return scrollEnabled
|
|
159
|
-
}
|
|
205
|
+
override fun canScrollVertically(direction: Int): Boolean = scrollEnabled
|
|
160
206
|
|
|
161
|
-
override fun canScrollHorizontally(direction: Int): Boolean
|
|
162
|
-
return scrollEnabled
|
|
163
|
-
}
|
|
207
|
+
override fun canScrollHorizontally(direction: Int): Boolean = scrollEnabled
|
|
164
208
|
|
|
165
|
-
override fun onSelectionChanged(
|
|
209
|
+
override fun onSelectionChanged(
|
|
210
|
+
selStart: Int,
|
|
211
|
+
selEnd: Int,
|
|
212
|
+
) {
|
|
166
213
|
super.onSelectionChanged(selStart, selEnd)
|
|
167
214
|
selection?.onSelection(selStart, selEnd)
|
|
168
215
|
}
|
|
@@ -172,7 +219,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
172
219
|
inputMethodManager?.hideSoftInputFromWindow(windowToken, 0)
|
|
173
220
|
}
|
|
174
221
|
|
|
175
|
-
override fun onFocusChanged(
|
|
222
|
+
override fun onFocusChanged(
|
|
223
|
+
focused: Boolean,
|
|
224
|
+
direction: Int,
|
|
225
|
+
previouslyFocusedRect: Rect?,
|
|
226
|
+
) {
|
|
176
227
|
super.onFocusChanged(focused, direction, previouslyFocusedRect)
|
|
177
228
|
val context = context as ReactContext
|
|
178
229
|
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
@@ -191,10 +242,6 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
191
242
|
handleCustomCopy()
|
|
192
243
|
return true
|
|
193
244
|
}
|
|
194
|
-
android.R.id.paste -> {
|
|
195
|
-
handleCustomPaste()
|
|
196
|
-
return true
|
|
197
|
-
}
|
|
198
245
|
}
|
|
199
246
|
return super.onTextContextMenuItem(id)
|
|
200
247
|
}
|
|
@@ -214,16 +261,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
214
261
|
}
|
|
215
262
|
}
|
|
216
263
|
|
|
217
|
-
|
|
218
|
-
val
|
|
219
|
-
if (!clipboard.hasPrimaryClip()) return
|
|
220
|
-
|
|
221
|
-
val clip = clipboard.primaryClip
|
|
222
|
-
val item = clip?.getItemAt(0)
|
|
223
|
-
val htmlText = item?.htmlText
|
|
264
|
+
fun handleTextPaste(item: ClipData.Item) {
|
|
265
|
+
val htmlText = item.htmlText
|
|
224
266
|
val currentText = text as Spannable
|
|
225
|
-
val start =
|
|
226
|
-
val end =
|
|
267
|
+
val start = selectionStart.coerceAtLeast(0)
|
|
268
|
+
val end = selectionEnd.coerceAtLeast(0)
|
|
227
269
|
|
|
228
270
|
if (htmlText != null) {
|
|
229
271
|
val parsedText = parseText(htmlText)
|
|
@@ -234,11 +276,14 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
234
276
|
}
|
|
235
277
|
}
|
|
236
278
|
|
|
237
|
-
|
|
238
|
-
|
|
279
|
+
if (item.text == null) return
|
|
280
|
+
val lengthBefore = currentText.length
|
|
239
281
|
val finalText = currentText.mergeSpannables(start, end, item.text.toString())
|
|
240
282
|
setValue(finalText)
|
|
241
|
-
|
|
283
|
+
|
|
284
|
+
// Detect links in the newly pasted range
|
|
285
|
+
val finalEndIndex = start + finalText.length - lengthBefore
|
|
286
|
+
parametrizedStyles?.detectLinksInRange(finalText, start, finalEndIndex)
|
|
242
287
|
}
|
|
243
288
|
|
|
244
289
|
fun requestFocusProgrammatically() {
|
|
@@ -252,7 +297,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
252
297
|
if (!isHtml) return text
|
|
253
298
|
|
|
254
299
|
try {
|
|
255
|
-
val parsed = EnrichedParser.fromHtml(text.toString(), htmlStyle,
|
|
300
|
+
val parsed = EnrichedParser.fromHtml(text.toString(), htmlStyle, spannableFactory)
|
|
256
301
|
val withoutLastNewLine = parsed.trimEnd('\n')
|
|
257
302
|
return withoutLastNewLine
|
|
258
303
|
} catch (e: Exception) {
|
|
@@ -269,14 +314,43 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
269
314
|
setText(newText)
|
|
270
315
|
|
|
271
316
|
observeAsyncImages()
|
|
272
|
-
// Assign SpanWatcher one more time as our previous spannable has been replaced
|
|
273
|
-
addSpanWatcher(EnrichedSpanWatcher(this))
|
|
274
317
|
|
|
275
318
|
// Scroll to the last line of text
|
|
276
319
|
setSelection(text?.length ?: 0)
|
|
277
320
|
}
|
|
278
321
|
}
|
|
279
322
|
|
|
323
|
+
fun setCustomSelection(
|
|
324
|
+
visibleStart: Int,
|
|
325
|
+
visibleEnd: Int,
|
|
326
|
+
) {
|
|
327
|
+
val actualStart = getActualIndex(visibleStart)
|
|
328
|
+
val actualEnd = getActualIndex(visibleEnd)
|
|
329
|
+
|
|
330
|
+
setSelection(actualStart, actualEnd)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Helper: Walks through the string skipping ZWSPs to find the Nth visible character
|
|
334
|
+
private fun getActualIndex(visibleIndex: Int): Int {
|
|
335
|
+
val currentText = text as Spannable
|
|
336
|
+
var currentVisibleCount = 0
|
|
337
|
+
var actualIndex = 0
|
|
338
|
+
|
|
339
|
+
while (actualIndex < currentText.length) {
|
|
340
|
+
if (currentVisibleCount == visibleIndex) {
|
|
341
|
+
return actualIndex
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// If the current char is not a hidden space, it counts towards our visible index
|
|
345
|
+
if (currentText[actualIndex] != EnrichedConstants.ZWS) {
|
|
346
|
+
currentVisibleCount++
|
|
347
|
+
}
|
|
348
|
+
actualIndex++
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return actualIndex
|
|
352
|
+
}
|
|
353
|
+
|
|
280
354
|
/**
|
|
281
355
|
* Finds all async images in the current text and sets up listeners
|
|
282
356
|
* to redraw the text layout when they finish downloading.
|
|
@@ -284,7 +358,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
284
358
|
private fun observeAsyncImages() {
|
|
285
359
|
val liveText = text ?: return
|
|
286
360
|
|
|
287
|
-
val spans = liveText.getSpans(0, liveText.length,
|
|
361
|
+
val spans = liveText.getSpans(0, liveText.length, EnrichedInputImageSpan::class.java)
|
|
288
362
|
|
|
289
363
|
for (span in spans) {
|
|
290
364
|
span.observeAsyncDrawableLoaded(liveText)
|
|
@@ -376,19 +450,50 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
376
450
|
}
|
|
377
451
|
|
|
378
452
|
fun setAutoCapitalize(flagName: String?) {
|
|
379
|
-
val flag =
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
453
|
+
val flag =
|
|
454
|
+
when (flagName) {
|
|
455
|
+
"none" -> InputType.TYPE_NULL
|
|
456
|
+
"sentences" -> InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
|
457
|
+
"words" -> InputType.TYPE_TEXT_FLAG_CAP_WORDS
|
|
458
|
+
"characters" -> InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
|
|
459
|
+
else -> InputType.TYPE_NULL
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
inputType = (
|
|
463
|
+
inputType and
|
|
464
|
+
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS.inv() and
|
|
465
|
+
InputType.TYPE_TEXT_FLAG_CAP_WORDS.inv() and
|
|
466
|
+
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES.inv()
|
|
467
|
+
) or if (flag == InputType.TYPE_NULL) 0 else flag
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
fun setLinkRegex(config: ReadableMap?) {
|
|
471
|
+
val patternStr = config?.getString("pattern")
|
|
472
|
+
if (patternStr == null) {
|
|
473
|
+
linkRegex = Patterns.WEB_URL
|
|
474
|
+
return
|
|
385
475
|
}
|
|
386
476
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
477
|
+
if (config.getBoolean("isDefault")) {
|
|
478
|
+
linkRegex = Patterns.WEB_URL
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (config.getBoolean("isDisabled")) {
|
|
483
|
+
linkRegex = null
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
var flags = 0
|
|
488
|
+
if (config.getBoolean("caseInsensitive")) flags = flags or Pattern.CASE_INSENSITIVE
|
|
489
|
+
if (config.getBoolean("dotAll")) flags = flags or Pattern.DOTALL
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
linkRegex = Pattern.compile("(?s).*?($patternStr).*", flags)
|
|
493
|
+
} catch (e: PatternSyntaxException) {
|
|
494
|
+
Log.w("EnrichedTextInputView", "Invalid link regex pattern: $patternStr")
|
|
495
|
+
linkRegex = Patterns.WEB_URL
|
|
496
|
+
}
|
|
392
497
|
}
|
|
393
498
|
|
|
394
499
|
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L283C2-L284C1
|
|
@@ -397,9 +502,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
397
502
|
// next layout() to be called. However, we do not perform a layout() after a requestLayout(), so
|
|
398
503
|
// we need to override isLayoutRequested to force EditText to scroll to the end of the new text
|
|
399
504
|
// immediately.
|
|
400
|
-
override fun isLayoutRequested(): Boolean
|
|
401
|
-
return false
|
|
402
|
-
}
|
|
505
|
+
override fun isLayoutRequested(): Boolean = false
|
|
403
506
|
|
|
404
507
|
fun afterUpdateTransaction() {
|
|
405
508
|
updateTypeface()
|
|
@@ -439,58 +542,76 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
439
542
|
EnrichedSpans.H1 -> paragraphStyles?.toggleStyle(EnrichedSpans.H1)
|
|
440
543
|
EnrichedSpans.H2 -> paragraphStyles?.toggleStyle(EnrichedSpans.H2)
|
|
441
544
|
EnrichedSpans.H3 -> paragraphStyles?.toggleStyle(EnrichedSpans.H3)
|
|
545
|
+
EnrichedSpans.H4 -> paragraphStyles?.toggleStyle(EnrichedSpans.H4)
|
|
546
|
+
EnrichedSpans.H5 -> paragraphStyles?.toggleStyle(EnrichedSpans.H5)
|
|
547
|
+
EnrichedSpans.H6 -> paragraphStyles?.toggleStyle(EnrichedSpans.H6)
|
|
442
548
|
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.toggleStyle(EnrichedSpans.CODE_BLOCK)
|
|
443
549
|
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.toggleStyle(EnrichedSpans.BLOCK_QUOTE)
|
|
444
550
|
EnrichedSpans.ORDERED_LIST -> listStyles?.toggleStyle(EnrichedSpans.ORDERED_LIST)
|
|
445
551
|
EnrichedSpans.UNORDERED_LIST -> listStyles?.toggleStyle(EnrichedSpans.UNORDERED_LIST)
|
|
552
|
+
EnrichedSpans.CHECKBOX_LIST -> listStyles?.toggleStyle(EnrichedSpans.CHECKBOX_LIST)
|
|
446
553
|
else -> Log.w("EnrichedTextInputView", "Unknown style: $name")
|
|
447
554
|
}
|
|
448
555
|
|
|
449
556
|
layoutManager.invalidateLayout()
|
|
450
557
|
}
|
|
451
558
|
|
|
452
|
-
private fun removeStyle(
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
559
|
+
private fun removeStyle(
|
|
560
|
+
name: String,
|
|
561
|
+
start: Int,
|
|
562
|
+
end: Int,
|
|
563
|
+
): Boolean {
|
|
564
|
+
val removed =
|
|
565
|
+
when (name) {
|
|
566
|
+
EnrichedSpans.BOLD -> inlineStyles?.removeStyle(EnrichedSpans.BOLD, start, end)
|
|
567
|
+
EnrichedSpans.ITALIC -> inlineStyles?.removeStyle(EnrichedSpans.ITALIC, start, end)
|
|
568
|
+
EnrichedSpans.UNDERLINE -> inlineStyles?.removeStyle(EnrichedSpans.UNDERLINE, start, end)
|
|
569
|
+
EnrichedSpans.STRIKETHROUGH -> inlineStyles?.removeStyle(EnrichedSpans.STRIKETHROUGH, start, end)
|
|
570
|
+
EnrichedSpans.INLINE_CODE -> inlineStyles?.removeStyle(EnrichedSpans.INLINE_CODE, start, end)
|
|
571
|
+
EnrichedSpans.H1 -> paragraphStyles?.removeStyle(EnrichedSpans.H1, start, end)
|
|
572
|
+
EnrichedSpans.H2 -> paragraphStyles?.removeStyle(EnrichedSpans.H2, start, end)
|
|
573
|
+
EnrichedSpans.H3 -> paragraphStyles?.removeStyle(EnrichedSpans.H3, start, end)
|
|
574
|
+
EnrichedSpans.H4 -> paragraphStyles?.removeStyle(EnrichedSpans.H4, start, end)
|
|
575
|
+
EnrichedSpans.H5 -> paragraphStyles?.removeStyle(EnrichedSpans.H5, start, end)
|
|
576
|
+
EnrichedSpans.H6 -> paragraphStyles?.removeStyle(EnrichedSpans.H6, start, end)
|
|
577
|
+
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.removeStyle(EnrichedSpans.CODE_BLOCK, start, end)
|
|
578
|
+
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.removeStyle(EnrichedSpans.BLOCK_QUOTE, start, end)
|
|
579
|
+
EnrichedSpans.ORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.ORDERED_LIST, start, end)
|
|
580
|
+
EnrichedSpans.UNORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.UNORDERED_LIST, start, end)
|
|
581
|
+
EnrichedSpans.CHECKBOX_LIST -> listStyles?.removeStyle(EnrichedSpans.CHECKBOX_LIST, start, end)
|
|
582
|
+
EnrichedSpans.LINK -> parametrizedStyles?.removeStyle(EnrichedSpans.LINK, start, end)
|
|
583
|
+
EnrichedSpans.IMAGE -> parametrizedStyles?.removeStyle(EnrichedSpans.IMAGE, start, end)
|
|
584
|
+
EnrichedSpans.MENTION -> parametrizedStyles?.removeStyle(EnrichedSpans.MENTION, start, end)
|
|
585
|
+
else -> false
|
|
586
|
+
}
|
|
471
587
|
|
|
472
588
|
return removed == true
|
|
473
589
|
}
|
|
474
590
|
|
|
475
591
|
private fun getTargetRange(name: String): Pair<Int, Int> {
|
|
476
|
-
val result =
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
592
|
+
val result =
|
|
593
|
+
when (name) {
|
|
594
|
+
EnrichedSpans.BOLD -> inlineStyles?.getStyleRange()
|
|
595
|
+
EnrichedSpans.ITALIC -> inlineStyles?.getStyleRange()
|
|
596
|
+
EnrichedSpans.UNDERLINE -> inlineStyles?.getStyleRange()
|
|
597
|
+
EnrichedSpans.STRIKETHROUGH -> inlineStyles?.getStyleRange()
|
|
598
|
+
EnrichedSpans.INLINE_CODE -> inlineStyles?.getStyleRange()
|
|
599
|
+
EnrichedSpans.H1 -> paragraphStyles?.getStyleRange()
|
|
600
|
+
EnrichedSpans.H2 -> paragraphStyles?.getStyleRange()
|
|
601
|
+
EnrichedSpans.H3 -> paragraphStyles?.getStyleRange()
|
|
602
|
+
EnrichedSpans.H4 -> paragraphStyles?.getStyleRange()
|
|
603
|
+
EnrichedSpans.H5 -> paragraphStyles?.getStyleRange()
|
|
604
|
+
EnrichedSpans.H6 -> paragraphStyles?.getStyleRange()
|
|
605
|
+
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.getStyleRange()
|
|
606
|
+
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.getStyleRange()
|
|
607
|
+
EnrichedSpans.ORDERED_LIST -> listStyles?.getStyleRange()
|
|
608
|
+
EnrichedSpans.UNORDERED_LIST -> listStyles?.getStyleRange()
|
|
609
|
+
EnrichedSpans.CHECKBOX_LIST -> listStyles?.getStyleRange()
|
|
610
|
+
EnrichedSpans.LINK -> parametrizedStyles?.getStyleRange()
|
|
611
|
+
EnrichedSpans.IMAGE -> parametrizedStyles?.getStyleRange()
|
|
612
|
+
EnrichedSpans.MENTION -> parametrizedStyles?.getStyleRange()
|
|
613
|
+
else -> Pair(0, 0)
|
|
614
|
+
}
|
|
494
615
|
|
|
495
616
|
return result ?: Pair(0, 0)
|
|
496
617
|
}
|
|
@@ -524,11 +645,12 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
524
645
|
|
|
525
646
|
val lengthAfter = text?.length ?: 0
|
|
526
647
|
val charactersRemoved = lengthBefore - lengthAfter
|
|
527
|
-
val finalEnd =
|
|
528
|
-
(
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
648
|
+
val finalEnd =
|
|
649
|
+
if (charactersRemoved > 0) {
|
|
650
|
+
(end - charactersRemoved).coerceAtLeast(0)
|
|
651
|
+
} else {
|
|
652
|
+
end
|
|
653
|
+
}
|
|
532
654
|
|
|
533
655
|
val finalStart = start.coerceAtLeast(0).coerceAtMost(finalEnd)
|
|
534
656
|
selection?.onSelection(finalStart, finalEnd)
|
|
@@ -537,12 +659,6 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
537
659
|
return true
|
|
538
660
|
}
|
|
539
661
|
|
|
540
|
-
private fun addSpanWatcher(watcher: EnrichedSpanWatcher) {
|
|
541
|
-
val spannable = text as Spannable
|
|
542
|
-
spannable.setSpan(watcher, 0, spannable.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
|
|
543
|
-
spanWatcher = watcher
|
|
544
|
-
}
|
|
545
|
-
|
|
546
662
|
fun verifyAndToggleStyle(name: String) {
|
|
547
663
|
val isValid = verifyStyle(name)
|
|
548
664
|
if (!isValid) return
|
|
@@ -550,14 +666,30 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
550
666
|
toggleStyle(name)
|
|
551
667
|
}
|
|
552
668
|
|
|
553
|
-
fun
|
|
669
|
+
fun toggleCheckboxListItem(checked: Boolean) {
|
|
670
|
+
val isValid = verifyStyle(EnrichedSpans.CHECKBOX_LIST)
|
|
671
|
+
if (!isValid) return
|
|
672
|
+
|
|
673
|
+
listStyles?.toggleCheckboxListStyle(checked)
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
fun addLink(
|
|
677
|
+
start: Int,
|
|
678
|
+
end: Int,
|
|
679
|
+
text: String,
|
|
680
|
+
url: String,
|
|
681
|
+
) {
|
|
554
682
|
val isValid = verifyStyle(EnrichedSpans.LINK)
|
|
555
683
|
if (!isValid) return
|
|
556
684
|
|
|
557
685
|
parametrizedStyles?.setLinkSpan(start, end, text, url)
|
|
558
686
|
}
|
|
559
687
|
|
|
560
|
-
fun addImage(
|
|
688
|
+
fun addImage(
|
|
689
|
+
src: String,
|
|
690
|
+
width: Float,
|
|
691
|
+
height: Float,
|
|
692
|
+
) {
|
|
561
693
|
val isValid = verifyStyle(EnrichedSpans.IMAGE)
|
|
562
694
|
if (!isValid) return
|
|
563
695
|
|
|
@@ -572,7 +704,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
572
704
|
parametrizedStyles?.startMention(indicator)
|
|
573
705
|
}
|
|
574
706
|
|
|
575
|
-
fun addMention(
|
|
707
|
+
fun addMention(
|
|
708
|
+
indicator: String,
|
|
709
|
+
text: String,
|
|
710
|
+
attributes: Map<String, String>,
|
|
711
|
+
) {
|
|
576
712
|
val isValid = verifyStyle(EnrichedSpans.MENTION)
|
|
577
713
|
if (!isValid) return
|
|
578
714
|
|
|
@@ -580,11 +716,12 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
580
716
|
}
|
|
581
717
|
|
|
582
718
|
fun requestHTML(requestId: Int) {
|
|
583
|
-
val html =
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
719
|
+
val html =
|
|
720
|
+
try {
|
|
721
|
+
EnrichedParser.toHtmlWithDefault(text)
|
|
722
|
+
} catch (e: Exception) {
|
|
723
|
+
null
|
|
724
|
+
}
|
|
588
725
|
|
|
589
726
|
val reactContext = context as ReactContext
|
|
590
727
|
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
@@ -604,45 +741,69 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
604
741
|
}
|
|
605
742
|
}
|
|
606
743
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
744
|
+
private fun forceScrollToSelection() {
|
|
745
|
+
val textLayout = layout ?: return
|
|
746
|
+
val cursorOffset = selectionStart
|
|
747
|
+
if (cursorOffset <= 0) return
|
|
611
748
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
749
|
+
val selectedLineIndex = textLayout.getLineForOffset(cursorOffset)
|
|
750
|
+
val selectedLineTop = textLayout.getLineTop(selectedLineIndex)
|
|
751
|
+
val selectedLineBottom = textLayout.getLineBottom(selectedLineIndex)
|
|
752
|
+
val visibleTextHeight = height - paddingTop - paddingBottom
|
|
616
753
|
|
|
617
|
-
|
|
754
|
+
if (visibleTextHeight <= 0) return
|
|
618
755
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
756
|
+
val visibleTop = scrollY
|
|
757
|
+
val visibleBottom = scrollY + visibleTextHeight
|
|
758
|
+
var targetScrollY = scrollY
|
|
622
759
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
760
|
+
if (selectedLineTop < visibleTop) {
|
|
761
|
+
targetScrollY = selectedLineTop
|
|
762
|
+
} else if (selectedLineBottom > visibleBottom) {
|
|
763
|
+
targetScrollY = selectedLineBottom - visibleTextHeight
|
|
764
|
+
}
|
|
628
765
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
766
|
+
val maxScrollY = (textLayout.height - visibleTextHeight).coerceAtLeast(0)
|
|
767
|
+
targetScrollY = targetScrollY.coerceIn(0, maxScrollY)
|
|
768
|
+
scrollTo(scrollX, targetScrollY)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
private fun isHeadingBold(
|
|
772
|
+
style: HtmlStyle,
|
|
773
|
+
span: EnrichedInputSpan,
|
|
774
|
+
): Boolean =
|
|
775
|
+
when (span) {
|
|
776
|
+
is EnrichedInputH1Span -> style.h1Bold
|
|
777
|
+
is EnrichedInputH2Span -> style.h2Bold
|
|
778
|
+
is EnrichedInputH3Span -> style.h3Bold
|
|
779
|
+
is EnrichedInputH4Span -> style.h4Bold
|
|
780
|
+
is EnrichedInputH5Span -> style.h5Bold
|
|
781
|
+
is EnrichedInputH6Span -> style.h6Bold
|
|
782
|
+
else -> false
|
|
632
783
|
}
|
|
633
784
|
|
|
634
|
-
private fun
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
785
|
+
private fun shouldRemoveBoldFromHeading(
|
|
786
|
+
span: EnrichedInputSpan,
|
|
787
|
+
prevStyle: HtmlStyle,
|
|
788
|
+
nextStyle: HtmlStyle,
|
|
789
|
+
): Boolean {
|
|
790
|
+
val wasBold = isHeadingBold(prevStyle, span)
|
|
791
|
+
val isNowBold = isHeadingBold(nextStyle, span)
|
|
638
792
|
|
|
793
|
+
return !wasBold && isNowBold
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
private fun reApplyHtmlStyleForSpans(
|
|
797
|
+
previousHtmlStyle: HtmlStyle,
|
|
798
|
+
nextHtmlStyle: HtmlStyle,
|
|
799
|
+
) {
|
|
639
800
|
val spannable = text as? Spannable ?: return
|
|
640
801
|
if (spannable.isEmpty()) return
|
|
641
802
|
|
|
642
803
|
var shouldEmitStateChange = false
|
|
643
804
|
|
|
644
805
|
runAsATransaction {
|
|
645
|
-
val spans = spannable.getSpans(0, spannable.length,
|
|
806
|
+
val spans = spannable.getSpans(0, spannable.length, EnrichedInputSpan::class.java)
|
|
646
807
|
for (span in spans) {
|
|
647
808
|
if (!span.dependsOnHtmlStyle) continue
|
|
648
809
|
|
|
@@ -652,7 +813,8 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
652
813
|
|
|
653
814
|
if (start == -1 || end == -1) continue
|
|
654
815
|
|
|
655
|
-
|
|
816
|
+
// Check if we need to remove explicit bold spans
|
|
817
|
+
if (shouldRemoveBoldFromHeading(span, previousHtmlStyle, nextHtmlStyle)) {
|
|
656
818
|
val isRemoved = removeStyle(EnrichedSpans.BOLD, start, end)
|
|
657
819
|
if (isRemoved) shouldEmitStateChange = true
|
|
658
820
|
}
|
|
@@ -673,6 +835,9 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
673
835
|
override fun onAttachedToWindow() {
|
|
674
836
|
super.onAttachedToWindow()
|
|
675
837
|
|
|
838
|
+
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L946
|
|
839
|
+
super.setTextIsSelectable(true)
|
|
840
|
+
|
|
676
841
|
if (autoFocus && !didAttachToWindow) {
|
|
677
842
|
requestFocusProgrammatically()
|
|
678
843
|
}
|