react-native-enriched 0.5.1 → 0.5.2
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/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt +20 -5
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSelection.kt +11 -6
- package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +8 -0
- package/ios/EnrichedTextInputView.h +1 -0
- package/ios/EnrichedTextInputView.mm +12 -12
- package/ios/inputTextView/InputTextView.mm +11 -0
- package/package.json +5 -2
|
@@ -65,6 +65,7 @@ import com.swmansion.enriched.textinput.utils.EnrichedSpanState
|
|
|
65
65
|
import com.swmansion.enriched.textinput.utils.RichContentReceiver
|
|
66
66
|
import com.swmansion.enriched.textinput.utils.mergeSpannables
|
|
67
67
|
import com.swmansion.enriched.textinput.utils.setCheckboxClickListener
|
|
68
|
+
import com.swmansion.enriched.textinput.utils.zwsCountBefore
|
|
68
69
|
import com.swmansion.enriched.textinput.watchers.EnrichedSpanWatcher
|
|
69
70
|
import com.swmansion.enriched.textinput.watchers.EnrichedTextWatcher
|
|
70
71
|
import java.util.regex.Pattern
|
|
@@ -623,13 +624,26 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
623
624
|
val start = selection?.start ?: return
|
|
624
625
|
val end = selection.end
|
|
625
626
|
val styleState = spanState?.getStyleStatePayload() ?: return
|
|
626
|
-
val
|
|
627
|
+
val currentText = text ?: return
|
|
628
|
+
val selectedText = currentText.subSequence(start, end).toString().replace(EnrichedConstants.ZWS_STRING, "")
|
|
629
|
+
|
|
630
|
+
val visibleStart = start - currentText.zwsCountBefore(start)
|
|
631
|
+
val visibleEnd = end - currentText.zwsCountBefore(end)
|
|
627
632
|
|
|
628
633
|
val reactContext = context as ReactContext
|
|
629
634
|
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
630
635
|
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
|
|
631
636
|
dispatcher?.dispatchEvent(
|
|
632
|
-
OnContextMenuItemPressEvent(
|
|
637
|
+
OnContextMenuItemPressEvent(
|
|
638
|
+
surfaceId,
|
|
639
|
+
id,
|
|
640
|
+
itemText,
|
|
641
|
+
selectedText,
|
|
642
|
+
visibleStart,
|
|
643
|
+
visibleEnd,
|
|
644
|
+
styleState,
|
|
645
|
+
experimentalSynchronousEvents,
|
|
646
|
+
),
|
|
633
647
|
)
|
|
634
648
|
}
|
|
635
649
|
|
|
@@ -819,14 +833,14 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
819
833
|
val isValid = verifyStyle(EnrichedSpans.LINK)
|
|
820
834
|
if (!isValid) return
|
|
821
835
|
|
|
822
|
-
parametrizedStyles?.setLinkSpan(start, end, text, url)
|
|
836
|
+
parametrizedStyles?.setLinkSpan(getActualIndex(start), getActualIndex(end), text, url)
|
|
823
837
|
}
|
|
824
838
|
|
|
825
839
|
fun removeLink(
|
|
826
840
|
start: Int,
|
|
827
841
|
end: Int,
|
|
828
842
|
) {
|
|
829
|
-
parametrizedStyles?.removeLinkSpans(start, end)
|
|
843
|
+
parametrizedStyles?.removeLinkSpans(getActualIndex(start), getActualIndex(end))
|
|
830
844
|
}
|
|
831
845
|
|
|
832
846
|
fun addImage(
|
|
@@ -980,7 +994,8 @@ class EnrichedTextInputView : AppCompatEditText {
|
|
|
980
994
|
super.onAttachedToWindow()
|
|
981
995
|
|
|
982
996
|
// https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L946
|
|
983
|
-
|
|
997
|
+
// setTextIsSelectable internally calls setText(), which fires afterTextChanged that should be marked as a transaction to avoid unwanted side effects
|
|
998
|
+
runAsATransaction { super.setTextIsSelectable(true) }
|
|
984
999
|
|
|
985
1000
|
if (autoFocus && !didAttachToWindow) {
|
|
986
1001
|
requestFocusProgrammatically()
|
|
@@ -233,14 +233,16 @@ class EnrichedSelection(
|
|
|
233
233
|
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
234
234
|
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
235
235
|
|
|
236
|
-
val
|
|
236
|
+
val visibleStart = start - editable.zwsCountBefore(start)
|
|
237
|
+
val visibleEnd = end - editable.zwsCountBefore(end)
|
|
238
|
+
val text = editable.substring(start, end).replace(EnrichedConstants.ZWS_STRING, "")
|
|
237
239
|
dispatcher?.dispatchEvent(
|
|
238
240
|
OnChangeSelectionEvent(
|
|
239
241
|
surfaceId,
|
|
240
242
|
view.id,
|
|
241
243
|
text,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
visibleStart,
|
|
245
|
+
visibleEnd,
|
|
244
246
|
view.experimentalSynchronousEvents,
|
|
245
247
|
),
|
|
246
248
|
)
|
|
@@ -252,7 +254,7 @@ class EnrichedSelection(
|
|
|
252
254
|
start: Int,
|
|
253
255
|
end: Int,
|
|
254
256
|
) {
|
|
255
|
-
val text = spannable.substring(start, end)
|
|
257
|
+
val text = spannable.substring(start, end).replace(EnrichedConstants.ZWS_STRING, "")
|
|
256
258
|
val url = span?.getUrl() ?: ""
|
|
257
259
|
|
|
258
260
|
// Prevents emitting unnecessary events
|
|
@@ -261,6 +263,9 @@ class EnrichedSelection(
|
|
|
261
263
|
previousLinkDetectedEvent.put("text", text)
|
|
262
264
|
previousLinkDetectedEvent.put("url", url)
|
|
263
265
|
|
|
266
|
+
val visibleStart = start - spannable.zwsCountBefore(start)
|
|
267
|
+
val visibleEnd = end - spannable.zwsCountBefore(end)
|
|
268
|
+
|
|
264
269
|
val context = view.context as ReactContext
|
|
265
270
|
val surfaceId = UIManagerHelper.getSurfaceId(context)
|
|
266
271
|
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
|
|
@@ -270,8 +275,8 @@ class EnrichedSelection(
|
|
|
270
275
|
view.id,
|
|
271
276
|
text,
|
|
272
277
|
url,
|
|
273
|
-
|
|
274
|
-
|
|
278
|
+
visibleStart,
|
|
279
|
+
visibleEnd,
|
|
275
280
|
view.experimentalSynchronousEvents,
|
|
276
281
|
),
|
|
277
282
|
)
|
|
@@ -3,6 +3,14 @@ package com.swmansion.enriched.textinput.utils
|
|
|
3
3
|
import android.text.SpannableStringBuilder
|
|
4
4
|
import com.swmansion.enriched.common.EnrichedConstants
|
|
5
5
|
|
|
6
|
+
fun CharSequence.zwsCountBefore(index: Int): Int {
|
|
7
|
+
var count = 0
|
|
8
|
+
for (i in 0 until index) {
|
|
9
|
+
if (this[i] == EnrichedConstants.ZWS) count++
|
|
10
|
+
}
|
|
11
|
+
return count
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
// Removes zero-width spaces from the given range in the SpannableStringBuilder without affecting spans
|
|
7
15
|
fun SpannableStringBuilder.removeZWS(
|
|
8
16
|
start: Int,
|
|
@@ -40,6 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
40
40
|
- (void)emitOnMentionEvent:(NSString *)indicator text:(nullable NSString *)text;
|
|
41
41
|
- (void)emitOnPasteImagesEvent:(NSArray<NSDictionary *> *)images;
|
|
42
42
|
- (void)anyTextMayHaveBeenModified;
|
|
43
|
+
- (void)scheduleRelayoutIfNeeded;
|
|
43
44
|
- (BOOL)handleStyleBlocksAndConflicts:(StyleType)type range:(NSRange)range;
|
|
44
45
|
- (NSArray<NSNumber *> *)getPresentStyleTypesFrom:(NSArray<NSNumber *> *)types
|
|
45
46
|
range:(NSRange)range;
|
|
@@ -717,18 +717,6 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
717
717
|
// now set the new config
|
|
718
718
|
config = newConfig;
|
|
719
719
|
|
|
720
|
-
// no emitting during styles reload
|
|
721
|
-
blockEmitting = YES;
|
|
722
|
-
|
|
723
|
-
// make sure everything is sound in the html
|
|
724
|
-
NSString *initiallyProcessedHtml =
|
|
725
|
-
[parser initiallyProcessHtml:currentHtml];
|
|
726
|
-
if (initiallyProcessedHtml != nullptr) {
|
|
727
|
-
[parser replaceWholeFromHtml:initiallyProcessedHtml];
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
blockEmitting = NO;
|
|
731
|
-
|
|
732
720
|
// fill the typing attributes with style props
|
|
733
721
|
defaultTypingAttributes[NSForegroundColorAttributeName] =
|
|
734
722
|
[config primaryColor];
|
|
@@ -742,6 +730,18 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
|
|
|
742
730
|
defaultPStyle.minimumLineHeight = [config scaledPrimaryLineHeight];
|
|
743
731
|
defaultTypingAttributes[NSParagraphStyleAttributeName] = defaultPStyle;
|
|
744
732
|
|
|
733
|
+
// no emitting during styles reload
|
|
734
|
+
blockEmitting = YES;
|
|
735
|
+
|
|
736
|
+
// make sure everything is sound in the html
|
|
737
|
+
NSString *initiallyProcessedHtml =
|
|
738
|
+
[parser initiallyProcessHtml:currentHtml];
|
|
739
|
+
if (initiallyProcessedHtml != nullptr) {
|
|
740
|
+
[parser replaceWholeFromHtml:initiallyProcessedHtml];
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
blockEmitting = NO;
|
|
744
|
+
|
|
745
745
|
textView.typingAttributes = defaultTypingAttributes;
|
|
746
746
|
textView.selectedRange = prevSelectedRange;
|
|
747
747
|
|
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
|
|
7
7
|
@implementation InputTextView
|
|
8
8
|
|
|
9
|
+
- (void)layoutSubviews {
|
|
10
|
+
[super layoutSubviews];
|
|
11
|
+
// UITextView resets contentSize during its own layout pass (triggered when
|
|
12
|
+
// the frame is set on first mount). Re-schedule a relayout so our explicit
|
|
13
|
+
// contentSize is applied after UITextView finishes its internal layout.
|
|
14
|
+
EnrichedTextInputView *input = (EnrichedTextInputView *)_input;
|
|
15
|
+
if (input != nil) {
|
|
16
|
+
[input scheduleRelayoutIfNeeded];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
9
20
|
- (void)copy:(id)sender {
|
|
10
21
|
EnrichedTextInputView *typedInput = (EnrichedTextInputView *)_input;
|
|
11
22
|
if (typedInput == nullptr) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-enriched",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Rich Text Editor component for React Native",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
@@ -49,7 +49,10 @@
|
|
|
49
49
|
"prepare": "bob build",
|
|
50
50
|
"release": "release-it",
|
|
51
51
|
"android-studio": "open -a 'Android Studio' apps/example/android",
|
|
52
|
-
"xcode": "open -a 'Xcode' apps/example/ios/EnrichedTextInputExample.xcworkspace"
|
|
52
|
+
"xcode": "open -a 'Xcode' apps/example/ios/EnrichedTextInputExample.xcworkspace",
|
|
53
|
+
"test:e2e": ".maestro/scripts/run-tests-all.sh",
|
|
54
|
+
"test:e2e:android": ".maestro/scripts/run-tests.sh --platform android",
|
|
55
|
+
"test:e2e:ios": ".maestro/scripts/run-tests.sh --platform ios"
|
|
53
56
|
},
|
|
54
57
|
"keywords": [
|
|
55
58
|
"react-native",
|