react-native-enriched 0.2.0 → 0.3.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 +16 -17
- 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/EventEmitters.cpp +156 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
- package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/Props.h +194 -0
- package/android/lint.gradle +70 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputConnectionWrapper.kt +140 -0
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputView.kt +304 -83
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewLayoutManager.kt +3 -1
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewManager.kt +166 -51
- package/android/src/main/java/com/swmansion/enriched/EnrichedTextInputViewPackage.kt +1 -3
- package/android/src/main/java/com/swmansion/enriched/MeasurementStore.kt +70 -21
- package/android/src/main/java/com/swmansion/enriched/events/MentionHandler.kt +21 -11
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +8 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeSelectionEvent.kt +10 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateDeprecatedEvent.kt +21 -0
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +9 -12
- package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +10 -10
- package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +7 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +7 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnInputKeyPressEvent.kt +27 -0
- package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +13 -11
- package/android/src/main/java/com/swmansion/enriched/events/OnMentionDetectedEvent.kt +10 -9
- package/android/src/main/java/com/swmansion/enriched/events/OnMentionEvent.kt +9 -8
- package/android/src/main/java/com/swmansion/enriched/events/OnRequestHtmlResultEvent.kt +32 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +24 -5
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedCodeBlockSpan.kt +10 -2
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH4Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH5Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH6Span.kt +24 -0
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedImageSpan.kt +34 -17
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +10 -4
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +14 -11
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedOrderedListSpan.kt +18 -11
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +174 -72
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +7 -1
- package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnorderedListSpan.kt +11 -5
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +3 -2
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +5 -0
- package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +1 -2
- package/android/src/main/java/com/swmansion/enriched/spans/utils/ForceRedrawSpan.kt +2 -1
- package/android/src/main/java/com/swmansion/enriched/styles/HtmlStyle.kt +155 -20
- package/android/src/main/java/com/swmansion/enriched/styles/InlineStyles.kt +25 -8
- package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +60 -20
- package/android/src/main/java/com/swmansion/enriched/styles/ParagraphStyles.kt +161 -25
- package/android/src/main/java/com/swmansion/enriched/styles/ParametrizedStyles.kt +128 -52
- package/android/src/main/java/com/swmansion/enriched/utils/AsyncDrawable.kt +10 -7
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedConstants.kt +11 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedEditableFactory.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedParser.java +136 -87
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSelection.kt +71 -42
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +183 -48
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannable.kt +82 -0
- package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpannableStringBuilder.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +0 -70
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedSpanWatcher.kt +46 -14
- package/android/src/main/java/com/swmansion/enriched/watchers/EnrichedTextWatcher.kt +34 -11
- package/android/src/main/new_arch/CMakeLists.txt +6 -0
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +6 -6
- package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +6 -6
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputComponentDescriptor.h +19 -19
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.cpp +40 -51
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputMeasurementManager.h +13 -15
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.cpp +23 -21
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputShadowNode.h +35 -36
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.cpp +4 -4
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/EnrichedTextInputState.h +13 -14
- package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +33 -14
- package/ios/EnrichedTextInputView.h +26 -14
- package/ios/EnrichedTextInputView.mm +1209 -586
- package/ios/config/InputConfig.h +24 -6
- package/ios/config/InputConfig.mm +154 -38
- package/ios/{utils → extensions}/ColorExtension.mm +7 -5
- package/ios/extensions/FontExtension.mm +106 -0
- package/ios/{utils → extensions}/LayoutManagerExtension.h +1 -1
- package/ios/extensions/LayoutManagerExtension.mm +396 -0
- package/ios/{utils → extensions}/StringExtension.mm +19 -16
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +156 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +147 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.cpp +10 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/Props.h +194 -0
- package/ios/generated/RNEnrichedTextInputViewSpec/RCTComponentViewHelpers.h +95 -0
- package/ios/inputParser/InputParser.h +5 -5
- package/ios/inputParser/InputParser.mm +864 -380
- package/ios/inputTextView/InputTextView.h +1 -1
- package/ios/inputTextView/InputTextView.mm +100 -59
- package/ios/{utils → interfaces}/BaseStyleProtocol.h +2 -2
- package/ios/interfaces/ImageAttachment.h +10 -0
- package/ios/interfaces/ImageAttachment.mm +36 -0
- package/ios/interfaces/LinkRegexConfig.h +19 -0
- package/ios/interfaces/LinkRegexConfig.mm +37 -0
- package/ios/interfaces/MediaAttachment.h +23 -0
- package/ios/interfaces/MediaAttachment.mm +31 -0
- package/ios/{utils → interfaces}/MentionParams.h +0 -1
- package/ios/{utils → interfaces}/MentionStyleProps.mm +27 -20
- package/ios/{utils → interfaces}/StyleHeaders.h +37 -15
- package/ios/{utils → interfaces}/StyleTypeEnum.h +3 -0
- package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +11 -9
- package/ios/internals/EnrichedTextInputViewShadowNode.h +28 -25
- package/ios/internals/EnrichedTextInputViewShadowNode.mm +45 -40
- package/ios/internals/EnrichedTextInputViewState.h +3 -1
- package/ios/styles/BlockQuoteStyle.mm +189 -118
- package/ios/styles/BoldStyle.mm +110 -63
- package/ios/styles/CodeBlockStyle.mm +204 -128
- package/ios/styles/H1Style.mm +10 -4
- package/ios/styles/H2Style.mm +10 -4
- package/ios/styles/H3Style.mm +10 -4
- package/ios/styles/H4Style.mm +17 -0
- package/ios/styles/H5Style.mm +17 -0
- package/ios/styles/H6Style.mm +17 -0
- package/ios/styles/HeadingStyleBase.mm +148 -86
- package/ios/styles/ImageStyle.mm +75 -73
- package/ios/styles/InlineCodeStyle.mm +162 -88
- package/ios/styles/ItalicStyle.mm +76 -52
- package/ios/styles/LinkStyle.mm +411 -232
- package/ios/styles/MentionStyle.mm +363 -246
- package/ios/styles/OrderedListStyle.mm +171 -106
- package/ios/styles/StrikethroughStyle.mm +52 -35
- package/ios/styles/UnderlineStyle.mm +68 -46
- package/ios/styles/UnorderedListStyle.mm +169 -106
- package/ios/utils/OccurenceUtils.h +42 -42
- package/ios/utils/OccurenceUtils.mm +142 -119
- package/ios/utils/ParagraphAttributesUtils.h +10 -2
- package/ios/utils/ParagraphAttributesUtils.mm +182 -71
- package/ios/utils/ParagraphsUtils.h +2 -1
- package/ios/utils/ParagraphsUtils.mm +41 -27
- package/ios/utils/TextInsertionUtils.h +13 -2
- package/ios/utils/TextInsertionUtils.mm +38 -20
- package/ios/utils/WordsUtils.h +2 -1
- package/ios/utils/WordsUtils.mm +32 -22
- package/ios/utils/ZeroWidthSpaceUtils.h +3 -1
- package/ios/utils/ZeroWidthSpaceUtils.mm +145 -79
- package/lib/module/EnrichedTextInput.js +61 -2
- package/lib/module/EnrichedTextInput.js.map +1 -1
- package/lib/module/EnrichedTextInputNativeComponent.ts +149 -12
- package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +12 -0
- package/lib/module/utils/normalizeHtmlStyle.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 +24 -14
- package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts +129 -12
- package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- 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/regexParser.d.ts +3 -0
- package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
- package/package.json +17 -6
- package/src/EnrichedTextInput.tsx +96 -13
- package/src/EnrichedTextInputNativeComponent.ts +149 -12
- package/src/index.tsx +2 -0
- package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +14 -2
- package/src/utils/regexParser.ts +56 -0
- package/ios/utils/FontExtension.mm +0 -91
- package/ios/utils/LayoutManagerExtension.mm +0 -286
- package/lib/module/normalizeHtmlStyle.js.map +0 -1
- package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
- package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
- package/ios/{utils → extensions}/ColorExtension.h +0 -0
- package/ios/{utils → extensions}/FontExtension.h +0 -0
- package/ios/{utils → extensions}/StringExtension.h +1 -1
- 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/{utils → interfaces}/MentionParams.mm +0 -0
- package/ios/{utils → interfaces}/MentionStyleProps.h +1 -1
- /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
|
@@ -13,12 +13,16 @@ 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
|
|
21
24
|
import com.facebook.react.bridge.ReactContext
|
|
25
|
+
import com.facebook.react.bridge.ReadableMap
|
|
22
26
|
import com.facebook.react.common.ReactConstants
|
|
23
27
|
import com.facebook.react.uimanager.PixelUtil
|
|
24
28
|
import com.facebook.react.uimanager.StateWrapper
|
|
@@ -29,22 +33,30 @@ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
|
|
29
33
|
import com.swmansion.enriched.events.MentionHandler
|
|
30
34
|
import com.swmansion.enriched.events.OnInputBlurEvent
|
|
31
35
|
import com.swmansion.enriched.events.OnInputFocusEvent
|
|
36
|
+
import com.swmansion.enriched.events.OnRequestHtmlResultEvent
|
|
37
|
+
import com.swmansion.enriched.spans.EnrichedH1Span
|
|
38
|
+
import com.swmansion.enriched.spans.EnrichedH2Span
|
|
39
|
+
import com.swmansion.enriched.spans.EnrichedH3Span
|
|
32
40
|
import com.swmansion.enriched.spans.EnrichedImageSpan
|
|
33
41
|
import com.swmansion.enriched.spans.EnrichedSpans
|
|
42
|
+
import com.swmansion.enriched.spans.interfaces.EnrichedSpan
|
|
43
|
+
import com.swmansion.enriched.styles.HtmlStyle
|
|
34
44
|
import com.swmansion.enriched.styles.InlineStyles
|
|
35
45
|
import com.swmansion.enriched.styles.ListStyles
|
|
36
46
|
import com.swmansion.enriched.styles.ParagraphStyles
|
|
37
47
|
import com.swmansion.enriched.styles.ParametrizedStyles
|
|
38
|
-
import com.swmansion.enriched.
|
|
48
|
+
import com.swmansion.enriched.utils.EnrichedConstants
|
|
49
|
+
import com.swmansion.enriched.utils.EnrichedEditableFactory
|
|
39
50
|
import com.swmansion.enriched.utils.EnrichedParser
|
|
40
51
|
import com.swmansion.enriched.utils.EnrichedSelection
|
|
41
52
|
import com.swmansion.enriched.utils.EnrichedSpanState
|
|
42
53
|
import com.swmansion.enriched.utils.mergeSpannables
|
|
43
54
|
import com.swmansion.enriched.watchers.EnrichedSpanWatcher
|
|
44
55
|
import com.swmansion.enriched.watchers.EnrichedTextWatcher
|
|
56
|
+
import java.util.regex.Pattern
|
|
57
|
+
import java.util.regex.PatternSyntaxException
|
|
45
58
|
import kotlin.math.ceil
|
|
46
59
|
|
|
47
|
-
|
|
48
60
|
class EnrichedTextInputView : AppCompatEditText {
|
|
49
61
|
var stateWrapper: StateWrapper? = null
|
|
50
62
|
val selection: EnrichedSelection? = EnrichedSelection(this)
|
|
@@ -59,10 +71,20 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
59
71
|
|
|
60
72
|
val mentionHandler: MentionHandler? = MentionHandler(this)
|
|
61
73
|
var htmlStyle: HtmlStyle = HtmlStyle(this, null)
|
|
74
|
+
set(value) {
|
|
75
|
+
if (field != value) {
|
|
76
|
+
val prev = field
|
|
77
|
+
field = value
|
|
78
|
+
reApplyHtmlStyleForSpans(prev, value)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var linkRegex: Pattern? = Patterns.WEB_URL
|
|
62
83
|
var spanWatcher: EnrichedSpanWatcher? = null
|
|
63
84
|
var layoutManager: EnrichedTextInputViewLayoutManager = EnrichedTextInputViewLayoutManager(this)
|
|
64
85
|
|
|
65
|
-
var shouldEmitHtml: Boolean =
|
|
86
|
+
var shouldEmitHtml: Boolean = false
|
|
87
|
+
var shouldEmitOnChangeText: Boolean = false
|
|
66
88
|
var experimentalSynchronousEvents: Boolean = false
|
|
67
89
|
|
|
68
90
|
var fontSize: Float? = null
|
|
@@ -89,11 +111,26 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
89
111
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
|
|
90
112
|
context,
|
|
91
113
|
attrs,
|
|
92
|
-
defStyleAttr
|
|
114
|
+
defStyleAttr,
|
|
93
115
|
) {
|
|
94
116
|
prepareComponent()
|
|
95
117
|
}
|
|
96
118
|
|
|
119
|
+
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
|
|
120
|
+
var inputConnection = super.onCreateInputConnection(outAttrs)
|
|
121
|
+
if (inputConnection != null) {
|
|
122
|
+
inputConnection =
|
|
123
|
+
EnrichedTextInputConnectionWrapper(
|
|
124
|
+
inputConnection,
|
|
125
|
+
context as ReactContext,
|
|
126
|
+
this,
|
|
127
|
+
experimentalSynchronousEvents,
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return inputConnection
|
|
132
|
+
}
|
|
133
|
+
|
|
97
134
|
init {
|
|
98
135
|
inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
99
136
|
}
|
|
@@ -112,7 +149,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
112
149
|
setPadding(0, 0, 0, 0)
|
|
113
150
|
setBackgroundColor(Color.TRANSPARENT)
|
|
114
151
|
|
|
115
|
-
|
|
152
|
+
// Ensure that every time new editable is created, it has EnrichedSpanWatcher attached
|
|
153
|
+
val spanWatcher = EnrichedSpanWatcher(this)
|
|
154
|
+
this.spanWatcher = spanWatcher
|
|
155
|
+
setEditableFactory(EnrichedEditableFactory(spanWatcher))
|
|
156
|
+
|
|
116
157
|
addTextChangedListener(EnrichedTextWatcher(this))
|
|
117
158
|
}
|
|
118
159
|
|
|
@@ -126,31 +167,32 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
126
167
|
this.parent.requestDisallowInterceptTouchEvent(true)
|
|
127
168
|
}
|
|
128
169
|
|
|
129
|
-
MotionEvent.ACTION_MOVE ->
|
|
170
|
+
MotionEvent.ACTION_MOVE -> {
|
|
130
171
|
if (detectScrollMovement) {
|
|
131
172
|
if (!canScrollVertically(-1) &&
|
|
132
173
|
!canScrollVertically(1) &&
|
|
133
174
|
!canScrollHorizontally(-1) &&
|
|
134
|
-
!canScrollHorizontally(1)
|
|
175
|
+
!canScrollHorizontally(1)
|
|
176
|
+
) {
|
|
135
177
|
// We cannot scroll, let parent views take care of these touches.
|
|
136
178
|
this.parent.requestDisallowInterceptTouchEvent(false)
|
|
137
179
|
}
|
|
138
180
|
detectScrollMovement = false
|
|
139
181
|
}
|
|
182
|
+
}
|
|
140
183
|
}
|
|
141
184
|
|
|
142
185
|
return super.onTouchEvent(ev)
|
|
143
186
|
}
|
|
144
187
|
|
|
145
|
-
override fun canScrollVertically(direction: Int): Boolean
|
|
146
|
-
return scrollEnabled
|
|
147
|
-
}
|
|
188
|
+
override fun canScrollVertically(direction: Int): Boolean = scrollEnabled
|
|
148
189
|
|
|
149
|
-
override fun canScrollHorizontally(direction: Int): Boolean
|
|
150
|
-
return scrollEnabled
|
|
151
|
-
}
|
|
190
|
+
override fun canScrollHorizontally(direction: Int): Boolean = scrollEnabled
|
|
152
191
|
|
|
153
|
-
override fun onSelectionChanged(
|
|
192
|
+
override fun onSelectionChanged(
|
|
193
|
+
selStart: Int,
|
|
194
|
+
selEnd: Int,
|
|
195
|
+
) {
|
|
154
196
|
super.onSelectionChanged(selStart, selEnd)
|
|
155
197
|
selection?.onSelection(selStart, selEnd)
|
|
156
198
|
}
|
|
@@ -160,7 +202,11 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
160
202
|
inputMethodManager?.hideSoftInputFromWindow(windowToken, 0)
|
|
161
203
|
}
|
|
162
204
|
|
|
163
|
-
override fun onFocusChanged(
|
|
205
|
+
override fun onFocusChanged(
|
|
206
|
+
focused: Boolean,
|
|
207
|
+
direction: Int,
|
|
208
|
+
previouslyFocusedRect: Rect?,
|
|
209
|
+
) {
|
|
164
210
|
super.onFocusChanged(focused, direction, previouslyFocusedRect)
|
|
165
211
|
val context = context as ReactContext
|
|
166
212
|
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
@@ -179,6 +225,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
179
225
|
handleCustomCopy()
|
|
180
226
|
return true
|
|
181
227
|
}
|
|
228
|
+
|
|
182
229
|
android.R.id.paste -> {
|
|
183
230
|
handleCustomPaste()
|
|
184
231
|
return true
|
|
@@ -224,9 +271,13 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
224
271
|
|
|
225
272
|
// Currently, we do not support pasting images
|
|
226
273
|
if (item?.text == null) return
|
|
274
|
+
val lengthBefore = currentText.length
|
|
227
275
|
val finalText = currentText.mergeSpannables(start, end, item.text.toString())
|
|
228
276
|
setValue(finalText)
|
|
229
|
-
|
|
277
|
+
|
|
278
|
+
// Detect links in the newly pasted range
|
|
279
|
+
val finalEndIndex = start + finalText.length - lengthBefore
|
|
280
|
+
parametrizedStyles?.detectLinksInRange(finalText, start, finalEndIndex)
|
|
230
281
|
}
|
|
231
282
|
|
|
232
283
|
fun requestFocusProgrammatically() {
|
|
@@ -257,14 +308,43 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
257
308
|
setText(newText)
|
|
258
309
|
|
|
259
310
|
observeAsyncImages()
|
|
260
|
-
// Assign SpanWatcher one more time as our previous spannable has been replaced
|
|
261
|
-
addSpanWatcher(EnrichedSpanWatcher(this))
|
|
262
311
|
|
|
263
312
|
// Scroll to the last line of text
|
|
264
313
|
setSelection(text?.length ?: 0)
|
|
265
314
|
}
|
|
266
315
|
}
|
|
267
316
|
|
|
317
|
+
fun setCustomSelection(
|
|
318
|
+
visibleStart: Int,
|
|
319
|
+
visibleEnd: Int,
|
|
320
|
+
) {
|
|
321
|
+
val actualStart = getActualIndex(visibleStart)
|
|
322
|
+
val actualEnd = getActualIndex(visibleEnd)
|
|
323
|
+
|
|
324
|
+
setSelection(actualStart, actualEnd)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Helper: Walks through the string skipping ZWSPs to find the Nth visible character
|
|
328
|
+
private fun getActualIndex(visibleIndex: Int): Int {
|
|
329
|
+
val currentText = text as Spannable
|
|
330
|
+
var currentVisibleCount = 0
|
|
331
|
+
var actualIndex = 0
|
|
332
|
+
|
|
333
|
+
while (actualIndex < currentText.length) {
|
|
334
|
+
if (currentVisibleCount == visibleIndex) {
|
|
335
|
+
return actualIndex
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// If the current char is not a hidden space, it counts towards our visible index
|
|
339
|
+
if (currentText[actualIndex] != EnrichedConstants.ZWS) {
|
|
340
|
+
currentVisibleCount++
|
|
341
|
+
}
|
|
342
|
+
actualIndex++
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return actualIndex
|
|
346
|
+
}
|
|
347
|
+
|
|
268
348
|
/**
|
|
269
349
|
* Finds all async images in the current text and sets up listeners
|
|
270
350
|
* to redraw the text layout when they finish downloading.
|
|
@@ -335,6 +415,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
335
415
|
// This ensured that newly created spans will take the new font size into account
|
|
336
416
|
htmlStyle.invalidateStyles()
|
|
337
417
|
layoutManager.invalidateLayout()
|
|
418
|
+
forceScrollToSelection()
|
|
338
419
|
}
|
|
339
420
|
|
|
340
421
|
fun setFontFamily(family: String?) {
|
|
@@ -363,19 +444,50 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
363
444
|
}
|
|
364
445
|
|
|
365
446
|
fun setAutoCapitalize(flagName: String?) {
|
|
366
|
-
val flag =
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
447
|
+
val flag =
|
|
448
|
+
when (flagName) {
|
|
449
|
+
"none" -> InputType.TYPE_NULL
|
|
450
|
+
"sentences" -> InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
|
|
451
|
+
"words" -> InputType.TYPE_TEXT_FLAG_CAP_WORDS
|
|
452
|
+
"characters" -> InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
|
|
453
|
+
else -> InputType.TYPE_NULL
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
inputType = (
|
|
457
|
+
inputType and
|
|
458
|
+
InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS.inv() and
|
|
459
|
+
InputType.TYPE_TEXT_FLAG_CAP_WORDS.inv() and
|
|
460
|
+
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES.inv()
|
|
461
|
+
) or if (flag == InputType.TYPE_NULL) 0 else flag
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
fun setLinkRegex(config: ReadableMap?) {
|
|
465
|
+
val patternStr = config?.getString("pattern")
|
|
466
|
+
if (patternStr == null) {
|
|
467
|
+
linkRegex = Patterns.WEB_URL
|
|
468
|
+
return
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (config.getBoolean("isDefault")) {
|
|
472
|
+
linkRegex = Patterns.WEB_URL
|
|
473
|
+
return
|
|
372
474
|
}
|
|
373
475
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
476
|
+
if (config.getBoolean("isDisabled")) {
|
|
477
|
+
linkRegex = null
|
|
478
|
+
return
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
var flags = 0
|
|
482
|
+
if (config.getBoolean("caseInsensitive")) flags = flags or Pattern.CASE_INSENSITIVE
|
|
483
|
+
if (config.getBoolean("dotAll")) flags = flags or Pattern.DOTALL
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
linkRegex = Pattern.compile("(?s).*?($patternStr).*", flags)
|
|
487
|
+
} catch (e: PatternSyntaxException) {
|
|
488
|
+
Log.w("EnrichedTextInputView", "Invalid link regex pattern: $patternStr")
|
|
489
|
+
linkRegex = Patterns.WEB_URL
|
|
490
|
+
}
|
|
379
491
|
}
|
|
380
492
|
|
|
381
493
|
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L283C2-L284C1
|
|
@@ -384,9 +496,7 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
384
496
|
// next layout() to be called. However, we do not perform a layout() after a requestLayout(), so
|
|
385
497
|
// we need to override isLayoutRequested to force EditText to scroll to the end of the new text
|
|
386
498
|
// immediately.
|
|
387
|
-
override fun isLayoutRequested(): Boolean
|
|
388
|
-
return false
|
|
389
|
-
}
|
|
499
|
+
override fun isLayoutRequested(): Boolean = false
|
|
390
500
|
|
|
391
501
|
fun afterUpdateTransaction() {
|
|
392
502
|
updateTypeface()
|
|
@@ -426,6 +536,9 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
426
536
|
EnrichedSpans.H1 -> paragraphStyles?.toggleStyle(EnrichedSpans.H1)
|
|
427
537
|
EnrichedSpans.H2 -> paragraphStyles?.toggleStyle(EnrichedSpans.H2)
|
|
428
538
|
EnrichedSpans.H3 -> paragraphStyles?.toggleStyle(EnrichedSpans.H3)
|
|
539
|
+
EnrichedSpans.H4 -> paragraphStyles?.toggleStyle(EnrichedSpans.H4)
|
|
540
|
+
EnrichedSpans.H5 -> paragraphStyles?.toggleStyle(EnrichedSpans.H5)
|
|
541
|
+
EnrichedSpans.H6 -> paragraphStyles?.toggleStyle(EnrichedSpans.H6)
|
|
429
542
|
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.toggleStyle(EnrichedSpans.CODE_BLOCK)
|
|
430
543
|
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.toggleStyle(EnrichedSpans.BLOCK_QUOTE)
|
|
431
544
|
EnrichedSpans.ORDERED_LIST -> listStyles?.toggleStyle(EnrichedSpans.ORDERED_LIST)
|
|
@@ -436,48 +549,60 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
436
549
|
layoutManager.invalidateLayout()
|
|
437
550
|
}
|
|
438
551
|
|
|
439
|
-
private fun removeStyle(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
552
|
+
private fun removeStyle(
|
|
553
|
+
name: String,
|
|
554
|
+
start: Int,
|
|
555
|
+
end: Int,
|
|
556
|
+
): Boolean {
|
|
557
|
+
val removed =
|
|
558
|
+
when (name) {
|
|
559
|
+
EnrichedSpans.BOLD -> inlineStyles?.removeStyle(EnrichedSpans.BOLD, start, end)
|
|
560
|
+
EnrichedSpans.ITALIC -> inlineStyles?.removeStyle(EnrichedSpans.ITALIC, start, end)
|
|
561
|
+
EnrichedSpans.UNDERLINE -> inlineStyles?.removeStyle(EnrichedSpans.UNDERLINE, start, end)
|
|
562
|
+
EnrichedSpans.STRIKETHROUGH -> inlineStyles?.removeStyle(EnrichedSpans.STRIKETHROUGH, start, end)
|
|
563
|
+
EnrichedSpans.INLINE_CODE -> inlineStyles?.removeStyle(EnrichedSpans.INLINE_CODE, start, end)
|
|
564
|
+
EnrichedSpans.H1 -> paragraphStyles?.removeStyle(EnrichedSpans.H1, start, end)
|
|
565
|
+
EnrichedSpans.H2 -> paragraphStyles?.removeStyle(EnrichedSpans.H2, start, end)
|
|
566
|
+
EnrichedSpans.H3 -> paragraphStyles?.removeStyle(EnrichedSpans.H3, start, end)
|
|
567
|
+
EnrichedSpans.H4 -> paragraphStyles?.removeStyle(EnrichedSpans.H4, start, end)
|
|
568
|
+
EnrichedSpans.H5 -> paragraphStyles?.removeStyle(EnrichedSpans.H5, start, end)
|
|
569
|
+
EnrichedSpans.H6 -> paragraphStyles?.removeStyle(EnrichedSpans.H6, start, end)
|
|
570
|
+
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.removeStyle(EnrichedSpans.CODE_BLOCK, start, end)
|
|
571
|
+
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.removeStyle(EnrichedSpans.BLOCK_QUOTE, start, end)
|
|
572
|
+
EnrichedSpans.ORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.ORDERED_LIST, start, end)
|
|
573
|
+
EnrichedSpans.UNORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.UNORDERED_LIST, start, end)
|
|
574
|
+
EnrichedSpans.LINK -> parametrizedStyles?.removeStyle(EnrichedSpans.LINK, start, end)
|
|
575
|
+
EnrichedSpans.IMAGE -> parametrizedStyles?.removeStyle(EnrichedSpans.IMAGE, start, end)
|
|
576
|
+
EnrichedSpans.MENTION -> parametrizedStyles?.removeStyle(EnrichedSpans.MENTION, start, end)
|
|
577
|
+
else -> false
|
|
578
|
+
}
|
|
458
579
|
|
|
459
580
|
return removed == true
|
|
460
581
|
}
|
|
461
582
|
|
|
462
583
|
private fun getTargetRange(name: String): Pair<Int, Int> {
|
|
463
|
-
val result =
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
584
|
+
val result =
|
|
585
|
+
when (name) {
|
|
586
|
+
EnrichedSpans.BOLD -> inlineStyles?.getStyleRange()
|
|
587
|
+
EnrichedSpans.ITALIC -> inlineStyles?.getStyleRange()
|
|
588
|
+
EnrichedSpans.UNDERLINE -> inlineStyles?.getStyleRange()
|
|
589
|
+
EnrichedSpans.STRIKETHROUGH -> inlineStyles?.getStyleRange()
|
|
590
|
+
EnrichedSpans.INLINE_CODE -> inlineStyles?.getStyleRange()
|
|
591
|
+
EnrichedSpans.H1 -> paragraphStyles?.getStyleRange()
|
|
592
|
+
EnrichedSpans.H2 -> paragraphStyles?.getStyleRange()
|
|
593
|
+
EnrichedSpans.H3 -> paragraphStyles?.getStyleRange()
|
|
594
|
+
EnrichedSpans.H4 -> paragraphStyles?.getStyleRange()
|
|
595
|
+
EnrichedSpans.H5 -> paragraphStyles?.getStyleRange()
|
|
596
|
+
EnrichedSpans.H6 -> paragraphStyles?.getStyleRange()
|
|
597
|
+
EnrichedSpans.CODE_BLOCK -> paragraphStyles?.getStyleRange()
|
|
598
|
+
EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.getStyleRange()
|
|
599
|
+
EnrichedSpans.ORDERED_LIST -> listStyles?.getStyleRange()
|
|
600
|
+
EnrichedSpans.UNORDERED_LIST -> listStyles?.getStyleRange()
|
|
601
|
+
EnrichedSpans.LINK -> parametrizedStyles?.getStyleRange()
|
|
602
|
+
EnrichedSpans.IMAGE -> parametrizedStyles?.getStyleRange()
|
|
603
|
+
EnrichedSpans.MENTION -> parametrizedStyles?.getStyleRange()
|
|
604
|
+
else -> Pair(0, 0)
|
|
605
|
+
}
|
|
481
606
|
|
|
482
607
|
return result ?: Pair(0, 0)
|
|
483
608
|
}
|
|
@@ -511,11 +636,12 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
511
636
|
|
|
512
637
|
val lengthAfter = text?.length ?: 0
|
|
513
638
|
val charactersRemoved = lengthBefore - lengthAfter
|
|
514
|
-
val finalEnd =
|
|
515
|
-
(
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
639
|
+
val finalEnd =
|
|
640
|
+
if (charactersRemoved > 0) {
|
|
641
|
+
(end - charactersRemoved).coerceAtLeast(0)
|
|
642
|
+
} else {
|
|
643
|
+
end
|
|
644
|
+
}
|
|
519
645
|
|
|
520
646
|
val finalStart = start.coerceAtLeast(0).coerceAtMost(finalEnd)
|
|
521
647
|
selection?.onSelection(finalStart, finalEnd)
|
|
@@ -524,12 +650,6 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
524
650
|
return true
|
|
525
651
|
}
|
|
526
652
|
|
|
527
|
-
private fun addSpanWatcher(watcher: EnrichedSpanWatcher) {
|
|
528
|
-
val spannable = text as Spannable
|
|
529
|
-
spannable.setSpan(watcher, 0, spannable.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
|
|
530
|
-
spanWatcher = watcher
|
|
531
|
-
}
|
|
532
|
-
|
|
533
653
|
fun verifyAndToggleStyle(name: String) {
|
|
534
654
|
val isValid = verifyStyle(name)
|
|
535
655
|
if (!isValid) return
|
|
@@ -537,14 +657,23 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
537
657
|
toggleStyle(name)
|
|
538
658
|
}
|
|
539
659
|
|
|
540
|
-
fun addLink(
|
|
660
|
+
fun addLink(
|
|
661
|
+
start: Int,
|
|
662
|
+
end: Int,
|
|
663
|
+
text: String,
|
|
664
|
+
url: String,
|
|
665
|
+
) {
|
|
541
666
|
val isValid = verifyStyle(EnrichedSpans.LINK)
|
|
542
667
|
if (!isValid) return
|
|
543
668
|
|
|
544
669
|
parametrizedStyles?.setLinkSpan(start, end, text, url)
|
|
545
670
|
}
|
|
546
671
|
|
|
547
|
-
fun addImage(
|
|
672
|
+
fun addImage(
|
|
673
|
+
src: String,
|
|
674
|
+
width: Float,
|
|
675
|
+
height: Float,
|
|
676
|
+
) {
|
|
548
677
|
val isValid = verifyStyle(EnrichedSpans.IMAGE)
|
|
549
678
|
if (!isValid) return
|
|
550
679
|
|
|
@@ -559,13 +688,31 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
559
688
|
parametrizedStyles?.startMention(indicator)
|
|
560
689
|
}
|
|
561
690
|
|
|
562
|
-
fun addMention(
|
|
691
|
+
fun addMention(
|
|
692
|
+
indicator: String,
|
|
693
|
+
text: String,
|
|
694
|
+
attributes: Map<String, String>,
|
|
695
|
+
) {
|
|
563
696
|
val isValid = verifyStyle(EnrichedSpans.MENTION)
|
|
564
697
|
if (!isValid) return
|
|
565
698
|
|
|
566
699
|
parametrizedStyles?.setMentionSpan(text, indicator, attributes)
|
|
567
700
|
}
|
|
568
701
|
|
|
702
|
+
fun requestHTML(requestId: Int) {
|
|
703
|
+
val html =
|
|
704
|
+
try {
|
|
705
|
+
EnrichedParser.toHtmlWithDefault(text)
|
|
706
|
+
} catch (e: Exception) {
|
|
707
|
+
null
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
val reactContext = context as ReactContext
|
|
711
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
712
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
713
|
+
dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, id, requestId, html, experimentalSynchronousEvents))
|
|
714
|
+
}
|
|
715
|
+
|
|
569
716
|
// Sometimes setting up style triggers many changes in sequence
|
|
570
717
|
// Eg. removing conflicting styles -> changing text -> applying spans
|
|
571
718
|
// In such scenario we want to prevent from handling side effects (eg. onTextChanged)
|
|
@@ -578,9 +725,83 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
578
725
|
}
|
|
579
726
|
}
|
|
580
727
|
|
|
728
|
+
private fun forceScrollToSelection() {
|
|
729
|
+
val textLayout = layout ?: return
|
|
730
|
+
val cursorOffset = selectionStart
|
|
731
|
+
if (cursorOffset <= 0) return
|
|
732
|
+
|
|
733
|
+
val selectedLineIndex = textLayout.getLineForOffset(cursorOffset)
|
|
734
|
+
val selectedLineTop = textLayout.getLineTop(selectedLineIndex)
|
|
735
|
+
val selectedLineBottom = textLayout.getLineBottom(selectedLineIndex)
|
|
736
|
+
val visibleTextHeight = height - paddingTop - paddingBottom
|
|
737
|
+
|
|
738
|
+
if (visibleTextHeight <= 0) return
|
|
739
|
+
|
|
740
|
+
val visibleTop = scrollY
|
|
741
|
+
val visibleBottom = scrollY + visibleTextHeight
|
|
742
|
+
var targetScrollY = scrollY
|
|
743
|
+
|
|
744
|
+
if (selectedLineTop < visibleTop) {
|
|
745
|
+
targetScrollY = selectedLineTop
|
|
746
|
+
} else if (selectedLineBottom > visibleBottom) {
|
|
747
|
+
targetScrollY = selectedLineBottom - visibleTextHeight
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
val maxScrollY = (textLayout.height - visibleTextHeight).coerceAtLeast(0)
|
|
751
|
+
targetScrollY = targetScrollY.coerceIn(0, maxScrollY)
|
|
752
|
+
scrollTo(scrollX, targetScrollY)
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
private fun reApplyHtmlStyleForSpans(
|
|
756
|
+
previousHtmlStyle: HtmlStyle,
|
|
757
|
+
nextHtmlStyle: HtmlStyle,
|
|
758
|
+
) {
|
|
759
|
+
val shouldRemoveBoldSpanFromH1Span = !previousHtmlStyle.h1Bold && nextHtmlStyle.h1Bold
|
|
760
|
+
val shouldRemoveBoldSpanFromH2Span = !previousHtmlStyle.h2Bold && nextHtmlStyle.h2Bold
|
|
761
|
+
val shouldRemoveBoldSpanFromH3Span = !previousHtmlStyle.h3Bold && nextHtmlStyle.h3Bold
|
|
762
|
+
|
|
763
|
+
val spannable = text as? Spannable ?: return
|
|
764
|
+
if (spannable.isEmpty()) return
|
|
765
|
+
|
|
766
|
+
var shouldEmitStateChange = false
|
|
767
|
+
|
|
768
|
+
runAsATransaction {
|
|
769
|
+
val spans = spannable.getSpans(0, spannable.length, EnrichedSpan::class.java)
|
|
770
|
+
for (span in spans) {
|
|
771
|
+
if (!span.dependsOnHtmlStyle) continue
|
|
772
|
+
|
|
773
|
+
val start = spannable.getSpanStart(span)
|
|
774
|
+
val end = spannable.getSpanEnd(span)
|
|
775
|
+
val flags = spannable.getSpanFlags(span)
|
|
776
|
+
|
|
777
|
+
if (start == -1 || end == -1) continue
|
|
778
|
+
|
|
779
|
+
if ((span is EnrichedH1Span && shouldRemoveBoldSpanFromH1Span) || (span is EnrichedH2Span && shouldRemoveBoldSpanFromH2Span) ||
|
|
780
|
+
(span is EnrichedH3Span && shouldRemoveBoldSpanFromH3Span)
|
|
781
|
+
) {
|
|
782
|
+
val isRemoved = removeStyle(EnrichedSpans.BOLD, start, end)
|
|
783
|
+
if (isRemoved) shouldEmitStateChange = true
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
spannable.removeSpan(span)
|
|
787
|
+
val newSpan = span.rebuildWithStyle(htmlStyle)
|
|
788
|
+
spannable.setSpan(newSpan, start, end, flags)
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
if (shouldEmitStateChange) {
|
|
792
|
+
selection?.validateStyles()
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
layoutManager.invalidateLayout()
|
|
796
|
+
forceScrollToSelection()
|
|
797
|
+
}
|
|
798
|
+
|
|
581
799
|
override fun onAttachedToWindow() {
|
|
582
800
|
super.onAttachedToWindow()
|
|
583
801
|
|
|
802
|
+
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L946
|
|
803
|
+
super.setTextIsSelectable(true)
|
|
804
|
+
|
|
584
805
|
if (autoFocus && !didAttachToWindow) {
|
|
585
806
|
requestFocusProgrammatically()
|
|
586
807
|
}
|
|
@@ -2,7 +2,9 @@ package com.swmansion.enriched
|
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.Arguments
|
|
4
4
|
|
|
5
|
-
class EnrichedTextInputViewLayoutManager(
|
|
5
|
+
class EnrichedTextInputViewLayoutManager(
|
|
6
|
+
private val view: EnrichedTextInputView,
|
|
7
|
+
) {
|
|
6
8
|
private var forceHeightRecalculationCounter: Int = 0
|
|
7
9
|
|
|
8
10
|
fun invalidateLayout() {
|